Scribbling

Python: Object References 본문

Computer Science/Python

Python: Object References

focalpoint 2022. 4. 4. 12:21

 

ID operator returns the object's memory address. We use it to compare objects' identities.

morgan = {'name': 'hoesu', 'age':29}
hoesu = morgan

print(hoesu is morgan)

print(id(hoesu), id(morgan))

 

"==" operator calls __eq__() method in dict class and checks whether the objects have the same value or not.

morgan = {'name': 'hoesu', 'age':29}

anonymous = {'name': 'hoesu', 'age':29}

print(morgan == anonymous)
print(morgan is anonymous)

 

What is very important here is that 'Equality' does not necessarily mean 'Identity'.

 

Using mutable types as parameter defaults is a bad idea. Let's look at the below example.

class HauntedBus:

    def __init__(self, passengers=[]):
        self.passengers = passengers

    def pick(self, name):
        self.passengers.append(name)

    def drop(self, name):
        self.passengers.remove(name)

bus1 = HauntedBus()
bus1.pick('morgan')
print(bus1.passengers)

bus2 = HauntedBus()
print(bus2.passengers)

There's a guest in bus2 even though it never picked up anyone. What's wrong?

- self.passengers is aliasing of a default parameter.

- default parameter is function's property when it is defined (during import time). 

- If HauntedBus is initiated without parameters, the same default parameter is used.

 

Defensive programming with mutable parameters

class TwilightBus:

    def __init__(self, passengers=None):
        if passengers is None:
            self.passengers = []
        else:
            self.passengers = passengers

    def pick(self, name):
        self.passengers.append(name)

    def drop(self, name):
        self.passengers.remove(name)


people = ['morgan', 'JY', 'hoesu', 'HS']
bus1 = TwilightBus(people)
bus1.drop('morgan')
bus1.drop('HS')
print(bus1.passengers)
print(people)

We only dropped people from bus, but they are removed from the list at the same time. We have to be extra cautious when dealing with mutable parameters.

import copy
class TwilightBus:

    def __init__(self, passengers=None):
        if passengers is None:
            self.passengers = []
        else:
            # self.passengers = list(passengers)
            self.passengers = copy.deepcopy(passengers)

 

Now, about "del". "del" is to get rid of the name, not the object itself. In CPython, garbage collection is based on 'reference count'.

import weakref

s1 = {1, 2, 3}
s2 = s1

def bye():
    print('Garbage collected object')

e = weakref.finalize(s1, bye)
print(e.alive)

del s1
print(e.alive)
s2 = 'spam'
print(e.alive)

Above example clearly shows that an object is collected not by del, but when it is not reachable.

 

We used weakref in the above example. 'Weak Reference' means it references an object without increasing 'reference count'. As a result, it does not interfere with garbage collection.

 

WeakKeyDictionary, WeakValueDictionary, WeakSet are recommeded when creating weak references.

import weakref

class iamclass:
    instances = weakref.WeakSet()
    @classmethod
    def register(cls, instance):
        cls.instances.add(instance)

    def __init__(self):
        self.register(self)

    @classmethod
    def showAll(cls):
        print(cls.instances)

a = iamclass()
b = iamclass()
c = iamclass()
iamclass.showAll()

 

'Computer Science > Python' 카테고리의 다른 글

Python: Sequence Protocol  (0) 2022.04.06
Python: Pythonic Object  (0) 2022.04.05
Python: Decorator & Closure  (0) 2022.03.29
Python: Design Patterns  (0) 2022.03.25
Python: Memoryview function  (0) 2022.03.23