元类的“__call__”和实例的“__init__”之间的关系?
假设我有一个元类和一个使用这个元类的类:
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)
输出如下:
Meta: __call__ with (1,)
问题:
为什么 ProductClass.__init__
没有被触发...仅仅是因为 Meta.__call__
的原因吗?
更新:
现在,我为 ProductClass 添加了 __new__
方法:
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)
那么,是不是 Meta.__call__
有责任去调用 ProductClass 的 __new__
和 __init__
方法呢?
2 个回答
4
没错,是否调用 ProductClass.__init__
取决于 Meta.__call__
的决定(有时候可能不调用)。
引用一下 文档:
比如在元类中定义一个自定义的
__call__()
方法,可以让类在被调用时有不同的行为,比如不一定每次都创建一个新的实例。
那篇文档还提到了一种情况,就是元类的 __call__
可能会返回一个不同类的实例(也就是说,不一定是你例子中的 ProductClass
)。在这种情况下,自动调用 ProductClass.__init__
显然是不合适的。
8
在面向对象编程(OOP)中,扩展一个方法和重写一个方法是有区别的。你在你的元类 Meta
中所做的事情叫做重写,因为你定义了自己的 __call__
方法,但没有调用父类的 __call__
方法。如果你想要实现你想要的行为,就需要通过调用父类的方法来扩展 __call__
方法:
class Meta(type):
def __call__(cls, *args):
print "Meta: __call__ with", args
return super(Meta, cls).__call__(*args)