4

I came across the following code while reading about metaclasses here, although I don't know if this distinction is specific to metaclasses and I suspect that it is not:

class MetaBase(type):
    def __new__(mcl, name, bases, nmspc):
        print('MetaBase.__new__\n')
        return super(MetaBase, mcl).__new__(mcl, name, bases, nmspc)

    def __init__(cls, name, bases, nmspc):
        print('MetaBase.__init__\n')
        super(MetaBase, cls).__init__(name, bases, nmspc)

Note that the super().__init__() call omits the first argument. I'm guessing it's passed implicitly, as it's calling a method on whatever class is returned by super(). That's the way I've usually seen such calls constructed, although they typically involve self on a normal class rather than cls/mcl on a metaclass.

The super().__new__() call passes mcl explicitly, though. I don't understand why. The signatures look the same to me.

I am confused. Is super() returning something different in each case, perhaps? What's happening here, and should I expect to be bitten by this when overriding other magic methods?

[edit: Someone suggested that this is a duplicate of this question, which describes their different functionality. While the same difference is exhibited in some of the examples there, I see nothing stating why it exists or whether it's unique to __new__.]

Community
  • 1
  • 1
Andrew
  • 4,058
  • 4
  • 25
  • 37
  • 4
    `__new__` is a static method. `__init__` is an instance method. – spectras Jul 04 '16 at 23:31
  • 4
    Possible duplicate of [Python's use of \_\_new\_\_ and \_\_init\_\_?](http://stackoverflow.com/questions/674304/pythons-use-of-new-and-init) – spectras Jul 04 '16 at 23:34
  • About the edit, first sentence of official documentation for `__new__`: “[__new__() is a static method (special-cased so you need not declare it as such)](https://docs.python.org/3/reference/datamodel.html#object.__new__)” – spectras Jul 05 '16 at 00:06
  • Okay, that makes sense. Explain that in an answer and I'll accept it. I would also like to know if there are any other magically static methods to worry about, though -- as far as I can tell there are not, but apparently I can't trust that something that is not marked as static is in fact non-static. – Andrew Jul 05 '16 at 19:25

1 Answers1

2

The super().__new__() call passes mcl explicitly, though. I don't understand why. The signatures look the same to me.

The __new__ method is an oddity in that it is a staticmethod but has been special-cased so that you don't have to declare it as such. Being a staticmethod means that you have to explicitly pass in any variables that are needed (in this case, the metaclass).

In contrast, __init__ is like any other regular method. When you look it up from an instance, the instance is automatically passed in as the first argument. This works whether you call the parent directly with cls.__init__(name, bases, nmspc) or by using super() with super(MetaBase, cls).__init__(name, bases, nmspc). Both of those pass in cls as the first argument. That is how bound methods work for normal classes and for metaclasses. It doesn't matter whether super() is used or not.

So, the one odd case is __new__ because it is a staticmethod which by definition doesn't have automatic prepending behavior.

should I expect to be bitten by this when overriding other magic methods?

Staticmethods are somewhat rare. And among magic methods, __new__ is the only one I can think of. So, you should be safe :-)

Raymond Hettinger
  • 216,523
  • 63
  • 388
  • 485