7

Say I've got a metaclass and a class using it:

class Meta(type): def __call__(cls, *args): print "Meta: __call__ with", args class ProductClass(object): __metaclass__ = Meta def __init__(self, *args): print "ProductClass: __init__ with", args p = ProductClass(1) 

Output as follows:

Meta: __call__ with (1,) 

Question:

Why isn't ProductClass.__init__ triggered...just because of Meta.__call__?

UPDATE:

Now, I add __new__ for ProductClass:

class ProductClass(object): __metaclass__ = Meta def __new__(cls, *args): print "ProductClass: __new__ with", args return super(ProductClass, cls).__new__(cls, *args) def __init__(self, *args): print "ProductClass: __init__ with", args p = ProductClass(1) 

Is it Meta.__call__'s responsibility to call ProductClass's __new__ and __init__?

1
  • Your Meta.__call__() doesn't return anything. It needs to return an instance of the class it's passed as it first argument cls. This is usually accomplished by calling a method of the same name in its parent (aka base) class. That can be done by hardcoding it, i.e return type.__call__(, *args), or by using return super(Meta, cls).__call__(*args). Commented Mar 16, 2018 at 15:44

2 Answers 2

8

There is a difference in OOP between extending a method and overriding it, what you just did in your metaclass Meta is called overriding because you defined your __call__ method and you didn't call the parent __call__. to have the behavior that you want you have to extend __call__ method by calling the parent method:

class Meta(type): def __call__(cls, *args): print "Meta: __call__ with", args return super(Meta, cls).__call__(*args) 
Sign up to request clarification or add additional context in comments.

Comments

4

Yes - it's up to Meta.__call__ to call ProductClass.__init__ (or not, as the case may be).

To quote the documentation:

for example defining a custom __call__() method in the metaclass allows custom behavior when the class is called, e.g. not always creating a new instance.

That page also mentions a scenario where the metaclass's __call__ may return an instance of a different class (i.e. not ProductClass in your example). In this scenario it would clearly be inappropriate to call ProductClass.__init__ automatically.

3 Comments

what if I got a "new" in ProductClass? Will Meta's "call" call ProductClass's "new" and "init"? See my UPDATE.
And apparently, Meta's "call" is called first before ProductClass's "new".
The problem is that Meta.__call__ is required to call ProductClass.__new__ and ProductClass.__init__. Normally, type.__call__ does this for you, but when you define Meta.__call__ you override that behaviour, meaning it's not executed unless you do so. So, you're either required to call __new__ and __init__ yourself, or make a call to something like type.__call__(cls, *args).

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.