问题
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:
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)
回答2:
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.
来源:https://stackoverflow.com/questions/7485324/relationship-of-metaclasss-call-and-instances-init