explicit call to __init__(self) in subclass needed?

Andrew MacKeith andrew at mackeith.net
Fri Sep 18 14:58:46 EDT 2009



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.


See example below.

The __init__ must have the same arguments as the base class.

 >>> class Y(str):
...   def __init__(self):
...      self.color = 'blue'
...
 >>> y = Y('Parrot')
Traceback (most recent call last):
   File "<stdin>", line 1, in <module>
TypeError: __init__() takes exactly 1 argument (2 given)
 >>>
 >>> class Y(str):
...   def __init__(self, text):
...      self.color = 'blue'
...
 >>> y = Y('Parrot')
 >>> y
'Parrot'
 >>> y.color
'blue'
 >>> y[:3]
'Par'
 >>> y.size = 'small'
 >>>
 >>> y.__class__
<class '__main__.Y'>
 >>>

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'>
 >>>

Andrew



More information about the Python-list mailing list