Last active
April 28, 2017 16:10
-
-
Save benspaulding/af3feac287275618303132dbf84f5451 to your computer and use it in GitHub Desktop.
Python class vs instance attributes
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
>>> class Foo(object): | |
... # Immutable objects are fine as class attrs. | |
... mystr = 'a' | |
... myint = 1 | |
... mytpl = (1,) | |
... | |
... # But mutable objects often surprise you. | |
... mylst = [] | |
... mydct = {} | |
>>> foo = Foo() | |
>>> foo.__dict__ | |
{} | |
>>> Foo.__dict__ | |
dict_proxy({'__dict__': <attribute '__dict__' of 'Foo' objects>, | |
'__doc__': None, | |
'__module__': '__main__', | |
'__weakref__': <attribute '__weakref__' of 'Foo' objects>, | |
'mydct': {}, | |
'myint': 1, | |
'mylst': [], | |
'mystr': 'a', | |
'mytpl': (1,)}) | |
>>> # Here we simply make foo.mystr *point* to a new object 'b'. | |
>>> foo.mystr = 'b' | |
>>> foo.__dict__ | |
{'mystr': 'b'} | |
>>> Foo.__dict__ | |
dict_proxy({'__dict__': <attribute '__dict__' of 'Foo' objects>, | |
'__doc__': None, | |
'__module__': '__main__', | |
'__weakref__': <attribute '__weakref__' of 'Foo' objects>, | |
'mydct': {}, | |
'myint': 1, | |
'mylst': [], | |
'mystr': 'a', | |
'mytpl': (1,)}) | |
>>> # But here we are actually mutating the object that foo.mylst already points too. | |
>>> foo.mylst.append(2) | |
>>> foo.__dict__ | |
{'mystr': 'b'} | |
>>> Foo.__dict__ | |
dict_proxy({'__dict__': <attribute '__dict__' of 'Foo' objects>, | |
'__doc__': None, | |
'__module__': '__main__', | |
'__weakref__': <attribute '__weakref__' of 'Foo' objects>, | |
'mydct': {}, | |
'myint': 1, | |
'mylst': [2], | |
'mystr': 'a', | |
'mytpl': (1,)}) | |
>>> foo.mylst is Foo.mylst | |
True | |
>>> # But here we set it to a new object. | |
>>> foo.mylst = ['A new list!'] | |
>>> foo.mylst is Foo.mylst | |
False | |
>>> foo.__dict__ | |
{'mylst': ['A new list!'], 'mystr': 'b'} | |
>>> Foo.__dict__ | |
dict_proxy({'__dict__': <attribute '__dict__' of 'Foo' objects>, | |
'__doc__': None, | |
'__module__': '__main__', | |
'__weakref__': <attribute '__weakref__' of 'Foo' objects>, | |
'mydct': {}, | |
'myint': 1, | |
'mylst': [2], | |
'mystr': 'a', | |
'mytpl': (1,)}) | |
>>> # So you need to set the instance attribute first. The best way to do that | |
>>> # is in the __init__. | |
>>> import copy | |
>>> class Bar(Foo) | |
... def __init__(self, mylst=None, mydct=None, myset=None): | |
... # If you really want to set a default on the class, make a copy of it. | |
... if mylst is None: | |
... self.mylst = copy.deepcopy(self.mylst) | |
... if mydct is None: | |
... self.mydct = copy.deepcopy(self.mydct) | |
... | |
... # But the more common practice is to just put your default here | |
... # rather than on the class (and certainly *not* in the function kwargs!) | |
... if myset is None: | |
... self.myset = set() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment