Reputation: 3693
class MetaA(type):
def __new__(self, clsname, bases, clsdict):
print('meta __new__ called')
return super().__new__(self, clsname, bases, clsdict)
def __call__(self, *args, **kwargs):
print('meta __call__ called')
class A(metaclass=MetaA):
def __init__(self, x):
print('__init__ called')
self.x = x
meta __new__ called
a = A(['1'])
meta __call__ called
type(a)
NoneType
It appears that specifying a __call__
in the metaclass, blocks the __init__
of the main class.
How do I access the __init__
of the main class?
Upvotes: 0
Views: 69
Reputation: 104702
Your Meta.__call__
method doesn't return anything, which is the same as returning None
. That's why a
is None
at the end of your code.
The default behavior of type.__call__
(which you're overriding) is to create an instance and return it. If you still want that to happen, you need to call (and return the result of) super().__call__(*args, **kwargs)
, similar to what you do in Meta.__new__
.
def __call__(self, *args, **kwargs):
print('meta __call__ called')
return super().__call__(*args, **kwargs)
I suppose you could instead reimplement the behavior of type.__call__
(e.g. by calling the __new__
and __init__
methods of the class yourself), but unless you want to change some part of the default behavior, calling type.__call__
to do it via super()
is easier.
It's unrelated to your issue, but the first argument name you're using in your metaclass methods may lead you astray at some point. The __new__
method is called as if it was a classmethod, with the metaclass as its first argument. The __call__
method on the other hand is a normal method, being called on an instance of the metaclass, which is a class. I'd use meta
(or maybe mcls
) and cls
as the argument names, respectively, to avoid confusion. I reserve self
for regular classes, to refer to their own instances.
I guess if you wanted to reimplement type.__call__
, you could use self
to name the instance after you've created it:
def __call__(cls, *args, **kwargs):
print('meta __call__ called')
self = cls.__new__(cls, *args, **kwargs) # create the instance with __new__
if isinstance(self, cls): # if __new__ didn't do something strange
self.__init__(*args, **kwargs) # call __init__ on the instance
return self # then return it to the caller
Upvotes: 1