[Tutor] Modify inherited methods

spir ☣ denis.spir at gmail.com
Wed Apr 28 10:45:16 CEST 2010


On Wed, 28 Apr 2010 07:53:06 +0100
Walter Wefft <walterwefft at googlemail.com> wrote:

> Steven D'Aprano wrote:
>  > And for guru-level mastery, replace to call to dict.__init__ with ... 
> nothing at all, because dict.__init__ doesn't do anything.
>  >
>  >
>  >
> 
> (Sorry, should have sent to list).
> 
> I don't understand this - it must do something:
> 
> class MyDict1(dict):
> 
>     def __init__(self, *args, **kw):
>         pass
> 
> class MyDict2(dict):
> 
>     def __init__(self, *args, **kw):
>         dict.__init__(self, *args, **kw)
> 
> 
> d = MyDict1(y=2)
> print d
> {}
> 
> d = MyDict2(y=2)
> print d
> {'y': 2}
> 
> d = MyDict1({'x': 3})
> print d
> {}
> 
> d = MyDict2({'x': 3})
> print d
> {'x': 3}
> 
> Behaviour is different depending on whether you call the superclass 
> __init__ or not.
> 
> ?

Hem... this is a rather obscure point (I personly have it wrong each time I need to subtype builtin types). Maybe you find some enlightenment in the following code:

===============================
class MyDict0(dict):
    pass
class MyDict1(dict):
    def __init__(self, *args, **kw):
        pass
class MyDict2(dict):
    def __init__(self, *args, **kw):
        dict.__init__(self, *args, **kw)
===============================

d0 = MyDict0(a=1) ; d1 = MyDict1(a=1) ; d2 = MyDict2(a=1)
print d0,d1,d2 # ==> {'a': 1} {} {'a': 1}

In case you do not define any custom __init__ *at all*, dict will transparently feed an instance of your type with provided entries, if any. If you define one, and don't feed the collection yourself, you need to call dict's __init__ to do it for you.
This behaviour allows having custom params at init:

===============================
class MyDict(dict):
    def __init__(self, name="", **entries):
        self.name = name
        dict.__init__(self, **entries)
    def __str__(self):
        return "%s:%s" %(self.name,dict.__str__(self))
d = MyDict(name="XYZ", a=1,b=2,c=3)
print d	# ==> XYZ:{'a': 1, 'c': 3, 'b': 2}
===============================

But all this does not apply to "atomic" builtin types such as int:

===============================
class MyInt0(int):
    pass

class MyInt1(int):
    def __init__(self, *args):
        pass

class MyInt2(int):
    def __init__(self, *args):
        int.__init__(self, *args)

i0 = MyInt0(1) ; i1 = MyInt1(1) ; i2 = MyInt2(1)
print i0,i1,i2	# ==> 1 1 1
===============================

This runs by me with a message from the compiler: "DeprecationWarning: object.__init__() takes no parameters" (about the call to int.__init__).
I would like to understand the implementation and the reason for this difference.
This means one cannot customize the initialisation of a subtype of int like is done above for a subtype of dict:

===============================
class MyInt(int):
    def __init__(self, value=0, name=""):
        self.name = name
        int.__init__(self, value)
    def __str__(self):
        return "%s:%s" %(self.name,int.__str__(self))
#~ i = MyInt(name="XYZ", value=3)
i = MyInt(3, "XYZ")
print i	# ==> TypeError: an integer is required
===============================

(Keyword parameters will also be rejected.) This is due to the implicit execution of the builtin constructor, which requires definite parameters (here a value and possibly a base).
More info on this topic welcome :-)

Denis
________________________________

vit esse estrany ☣

spir.wikidot.com


More information about the Tutor mailing list