【问题标题】:Relationship of metaclass's "__call__" and instance's "__init__"?元类的“__call__”和实例的“__init__”的关系?
【发布时间】:2011-11-21 01:39:20
【问题描述】:

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

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)

调用ProductClass的__new____init__Meta.__call__的责任吗?

【问题讨论】:

  • 您的Meta.__call__() 不会返回任何内容。它需要返回它作为第一个参数cls 传递的类的实例。这通常是通过在其父类(也称为基类)中调用同名方法来完成的。这可以通过硬编码来完成,即return type.__call__(, *args),或使用return super(Meta, cls).__call__(*args)

标签: python metaclass


【解决方案1】:

在 OOP 中扩展一个方法和覆盖它是有区别的,你刚刚在你的元类 Meta 中所做的被称为覆盖,因为你定义了你的 __call__ 方法并且你没有调用父类 __call__。要获得您想要的行为,您必须通过调用父方法来扩展 __call__ 方法:

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

【讨论】:

    【解决方案2】:

    是的 - 取决于 Meta.__call__ 是否调用 ProductClass.__init__(或不调用,视情况而定)。

    引用documentation

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

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

    【讨论】:

    • 如果我在 ProductClass 中有一个“new”怎么办? Meta 的“call”会调用 ProductClass 的“new”和“init”吗?查看我的更新。
    • 显然,Meta 的“call”在 ProductClass 的“new”之前首先被调用。
    • 问题是Meta.__call__需要调用ProductClass.__new__ProductClass.__init__。通常,type.__call__ 会为您执行此操作,但是当您定义 Meta.__call__ 时,您会 覆盖 该行为,这意味着除非您这样做,否则它不会被执行。因此,您要么需要自己拨打__new____init__,要么拨打type.__call__(cls, *args) 之类的电话。
    猜你喜欢
    • 2018-09-19
    • 2012-12-15
    • 1970-01-01
    • 2012-10-09
    • 2012-03-28
    • 2022-10-14
    • 2012-07-04
    • 2021-12-19
    • 2019-02-11
    相关资源
    最近更新 更多