Relationship of metaclass's “__call__” and ins

2020-06-17 05:18发布

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__?

2条回答
smile是对你的礼貌
2楼-- · 2020-06-17 06:00

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.

查看更多
▲ chillily
3楼-- · 2020-06-17 06:14

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)
查看更多
登录 后发表回答