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
--
http://mail.python.org/mailman/listinfo/python-list

Reply via email to