Fastai v2 code walk-thru 5

Jeremy has also mentioned this issue briefly here: Fastai v2 chat - #183 by jeremy

AFAIK, because if __new__() is defined, it always goes before __init__(), and when creating a new subclass, the signature still belongs to its superclass if subclass didn’t define its own __new__().

class A():
    def __new__(cls, *args, **kwargs): return super().__new__(cls, *args, **kwargs)

class B(A):
    def __init__(self, a): self.a = a

B(a=1)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<some_obj_hash> in <module>
----> 1 B(a=1)

<another_obj_hash> in __new__(cls, *args, **kwargs)
      1 class A():
----> 2     def __new__(cls, *args, **kwargs): return super().__new__(cls, *args, **kwargs)

TypeError: object.__new__() takes exactly one argument (the type to instantiate)

The reasoning behind it is often pointed to Liskov substitution principle, despite Python is keen to duck-typing. Plus, this way seems more convenient for Python core developers when dealing with MRO (Method Resolution Order) and/or underlying C functions.

To imitate Jeremy’s solution with a non-meta superclass like A here, one way is to change subclass B verbosely:

class B(A):
    def __new__(cls, a, *args, **kwargs):
        res = super().__new__(cls, *args, **kwargs)
        res.__signature__ = inspect.signature(res.__init__)
        return res
    def __init__(self, a): self.a = a

Not only it’s annoying and error-prone to change subclasses, but B’s signature will have three arguments a, *args, **kwars rather than just one a. So probably another reason to have a meta superclass and change the signature in it.

1 Like