元类的“__call__”和实例的“__init__”的关系?

时间:2011-09-20 12:43:17

标签: python metaclass

说我有一个元类和一个使用它的类:

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 个答案:

答案 0 :(得分:7)

扩展方法和覆盖方法之间的OOP存在差异,您在元类Meta中刚刚执行的操作被称为覆盖,因为您定义了__call__方法并且没有调用父方法__call__。通过调用父方法来获得您希望必须扩展__call__方法的行为:

class Meta(type):
    def __call__(cls, *args):
        print "Meta: __call__ with", args
        return super(Meta, cls).__call__(*args)

答案 1 :(得分:4)

是的 - 最多Meta.__call__可以致电ProductClass.__init__(或不是,视具体情况而定)。

引用documentation

  

例如,在元类中定义自定义__call__()方法   允许在调用类时的自定义行为,例如不总是   创建一个新实例。

该页面还提到了一个场景,即元类的__call__可能会返回不同类的实例(例如,在您的示例中不是ProductClass)。在这种情况下,自动调用ProductClass.__init__显然是不合适的。