Python: extending int and MRO for __init__

2019-06-15 18:06发布

问题:

In Python, I'm trying to extend the builtin 'int' type. In doing so I want to pass in some keywoard arguments to the constructor, so I do this:

class C(int):
     def __init__(self, val, **kwargs):
         super(C, self).__init__(val)
         # Do something with kwargs here...

However while calling C(3) works fine, C(3, a=4) gives:

'a' is an invalid keyword argument for this function` 

and C.__mro__ returns the expected:

(<class '__main__.C'>, <type 'int'>, <type 'object'>)

But it seems that Python is trying to call int.__init__ first... Anyone know why? Is this a bug in the interpreter?

回答1:

The docs for the Python data model advise using __new__:

object.new(cls[, ...])

new() is intended mainly to allow subclasses of immutable types (like int, str, or tuple) to customize instance creation. It is also commonly overridden in custom metaclasses in order to customize class creation.

Something like this should do it for the example you gave:

class C(int):

    def __new__(cls, val, **kwargs):
        inst = super(C, cls).__new__(cls, val)
        inst.a = kwargs.get('a', 0)
        return inst


回答2:

You should be overriding "__new__", not "__init__" as ints are immutable.



回答3:

What everyone else (so far) said. Int are immutable, so you have to use new.

Also see (the accepted answers to):

  • increment int object
  • Why can't I subclass datetime.date?