explicit call to __init__(self) in subclass needed?
Bruno Desthuilliers
bruno.42.desthuilliers at websiteburo.invalid
Mon Sep 21 04:06:25 EDT 2009
Andrew MacKeith a écrit :
>
>
> Bruno Desthuilliers wrote:
>> Andrew MacKeith a écrit :
>>> I create a class like this in Python-2.6
>>>
>>> >>> class Y(str):
>>> ... def __init__(self, s):
>>> ... pass
>>> ...
>>> >>> y = Y('giraffe')
>>> >>> y
>>> 'giraffe'
>>> >>>
>>>
>>> How does the base class (str) get initialized with the value passed
>>> to Y.__init__() ?
>>
>> It happens in the __new__ method (which is the proper "constructor")
>>
>> class Y(str):
>> def __new__(cls, value, foo="foo"):
>> instance = str.__new__(cls, value)
>> instance.foo = foo
>> return instance
>>
>> def __repr__(self):
>> return "<%s(%s, %s)>" % (type(self).__name__, self, self.foo)
>>
>>
>>> Is this behavior specific to the str type, or do base classes not need
>>> to be explicitly initialized?
>>
>> When you override a method in a derived class, it's your
>> responsability to call on the parent(s) class(es) implementation.
>> __init__ is not an exception to that rule. The point is that since
>> __init__ works by mutating the newly created instance, it makes no
>> sense to have a distinct __init__ for immutable types - which have
>> their "value" set once for all at creation time.
>
> Thanks for the explanation, Bruno.
>
> I have been successfully using a class derived from str, and in that
> class I add a lot of extra data to the derived class instance in the
> __init__ method of the derived class, so it is possible to mutate the
> derived class __dict__, even if the base class data remains immutable.
Indeed. What I said was that Python builtins immutable types didn't use
the initializer, not that you couldn't use an initializer in derived
classes. I gave an example using __new__ because, quite often when
subclassing immutable types, peoples want to access the initial value
_before_ the call to the base class.
>
> See example below.
>
> The __init__ must have the same arguments as the base class.
The initializer (__init__) must have the same arguments as the
constructor (__new__). This is true for all and every classes.
(snip)
>
> But you can get bitten if you do something that returns a new object
>
> >>> y += 'Tail'
> >>> y
> 'ParrotTail'
> >>> y.color
> Traceback (most recent call last):
> File "<stdin>", line 1, in <module>
> AttributeError: 'str' object has no attribute 'color'
> >>>
> >>> y.__class__
> <type 'str'>
> >>>
You need to override a couple other __magic_methods__ to make this work.
You'll find relevant documentation here:
http://docs.python.org/reference/datamodel.html#special-method-names
In the above case, you want to override at least the __add__ method:
class Y(str):
def __new__(cls, value, foo="foo"):
instance = str.__new__(cls, value)
instance.foo = foo
return instance
def __repr__(self):
return "<%s(%s, %s)>" % (type(self).__name__, self, self.foo)
def __add__(self, other):
return type(self)(str(self) + other, self.foo)
>>> y = Y("foo", foo="bar")
>>> y
<Y(foo, bar)>
>>> y += "baaz"
>>> y
<Y(foobaaz, bar)>
>>>
HTH
More information about the Python-list
mailing list