I've found a strange issue with subclassing and dictionary updates in new-style classes:
Python 2.6.2 (r262:71605, Apr 14 2009, 22:40:02) [MSC v.1500 32 bit (Intel)] on
win32
>>> class a(object):
... def __init__(self, props={}):
... self.props = props
...
>>> class b(a):
... def __init__(self, val = None):
... super(b, self).__init__()
... self.props.update({'arg': val})
...
>>> class c(b):
... def __init__(self, val):
... super(c, self).__init__(val)
...
>>> b_inst = b(2)
>>> b_inst.props
{'arg': 2}
>>> c_inst = c(3)
>>> c_inst.props
{'arg': 3}
>>> b_inst.props
{'arg': 3}
>>>
In debug, in second call (c(3)
) you can see that within a
constructor self.props
is already equal to {'arg': 2}
, and when b
constructor is called after that, it becomes {'arg': 3}
for both objects!
also, the order of constructors calling is:
a, b # for b(2)
c, a, b # for c(3)
If you replace self.props.update()
with self.props = {'arg': val}
in b
constructor, everything will be OK, and will act as expected
But I really need to update this property, not to replace it.
props
should not have a default value like that. Do this instead:
class a(object):
def __init__(self, props=None):
if props is None:
props = {}
self.props = props
This is a common python "gotcha".
The short version: Do this:
class a(object):
def __init__(self, props=None):
self.props = props if props is not None else {}
class b(a):
def __init__(self, val = None):
super(b, self).__init__()
self.props.update({'arg': val})
class c(b):
def __init__(self, val):
super(c, self).__init__(val)
The long version:
The function definition is evaluated exactly once, so every time you call it the same default argument is used. For this to work like you expected, the default arguments would have to be evaluated every time a function is called. But instead Python generates a function object once and adds the defaults to the object ( as func_obj.func_defaults
)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With