“MetaClass”,“__ new__”,“cls”和“super” - 究竟是什么机制?

时间:2008-12-28 08:41:45

标签: python types metaclass super

我看过这样的帖子:

  1. What is a metaclass in Python?
  2. What are your (concrete) use-cases for metaclasses in Python?
  3. Python's Super is nifty, but you can't use it
  4. 但不知怎的,我感到困惑。许多混淆如:

    我何时以及为何要做以下事情?

    # Refer link1
    return super(MyType, cls).__new__(cls, name, bases, newattrs)
    

    # Refer link2
    return super(MetaSingleton, cls).__call__(*args, **kw)
    

    # Refer link2
    return type(self.__name__ + other.__name__, (self, other), {})
    

    超级工作如何完成?

    link1中的类注册表和取消注册是什么以及它究竟是如何工作的? (我认为它与singleton有关。我可能错了,来自C背景。我的编码风格仍然是功能和OO的混合。)

    类实例化(子类,元类,超类型)和方法调用的流程是什么(

    metaclass->__new__, metaclass->__init__, super->__new__, subclass->__init__ inherited from metaclass
    

    )具有良好评论的工作代码(虽然第一个链接非常接近,但它没有谈论cls关键字和超级(..)和注册表)。最好是具有多重继承的示例。

    P.S。:我将最后一部分作为代码,因为Stack Overflow格式化正在转换文本metaclass->__new__ 到元类 - >

2 个答案:

答案 0 :(得分:21)

好的,你在这里混合了很多概念!我将提出你遇到的一些具体问题。

一般来说,理解super,MRO和metclasses变得更加复杂,因为在最后几个版本的Python中,这个棘手的领域发生了很多变化。

Python's own documentation是一个非常好的参考,并且完全是最新的。有一个IBM developerWorks article作为介绍很好,并采用了更多基于教程的方法,但请注意它已经有五年了,并且花了很多时间讨论旧式的元类方法。 / p>

super 是您访问对象超类的方法。它比(例如)Java的super关键字更复杂,主要是因为Python中的多重继承。正如Super Considered Harmful所解释的那样,使用super()会导致您隐式使用超类的链,其顺序由Method Resolution Order(MRO)定义。

通过在类(而不是实例)上调用mro(),您可以轻松地查看类的MRO。请注意,元类不在对象的超类层次结构中。

Thomas'对元类here的描述非常好:

  

元类是类的类。   就像一个类定义一个实例   该类的行为,一个元类   定义类的行为方式。一类   是元类的一个实例。

在您给出的示例中,这是正在发生的事情:

  1. 正在调用__new__ 冒泡到了下一件事 MRO。在这种情况下,super(MyType, cls)将解析为type; 调用type.__new__可以让Python 完成它的正常实例 创作步骤。

  2. 此示例使用元类 强制执行单身人士。他是 覆盖__call__ 元类使每当一个类 实例被创建,他拦截 那,并且可以绕过实例 创造,如果已经有一个 (存储在cls.instance)。注意 在...中覆盖__new__ 元类不够好, 因为那只是在什么时候被召唤 创建。重写 课上__new__会奏效, 但是。

  3. 这显示了一种动态方式 创建一个类。这是他的 附加提供的类的名称 到创建的类名,和 将其添加到类层次结构中 太

  4. 我不确定你正在寻找什么样的代码示例,但这里有一个显示元类,继承和方法解析的简短示例:

    class MyMeta(type):
        def __new__(cls, name, bases, dct):
            print "meta: creating %s %s" % (name, bases)
            return type.__new__(cls, name, bases, dct)
    
        def meta_meth(cls):
            print "MyMeta.meta_meth"
    
        __repr__ = lambda c: c.__name__
    
    class A(object):
        __metaclass__ = MyMeta
        def __init__(self):
            super(A, self).__init__()
            print "A init"
    
        def meth(self):
            print "A.meth"
    
    class B(object):
        __metaclass__ = MyMeta
        def __init__(self):
            super(B, self).__init__()
            print "B init"
    
        def meth(self):
            print "B.meth"
    
    class C(A, B):
        __metaclass__ = MyMeta
        def __init__(self):
            super(C, self).__init__()
            print "C init"
    
    >>> c_obj = C()
    meta: creating A (<type 'object'>,)
    meta: creating B (<type 'object'>,)
    meta: creating C (A, B)
    B init
    A init
    C init
    >>> c_obj.meth()
    A.meth
    >>> C.meta_meth()
    MyMeta.meta_meth
    >>> c_obj.meta_meth()
    Traceback (most recent call last):
      File "mro.py", line 38, in <module>
        c_obj.meta_meth()
    AttributeError: 'C' object has no attribute 'meta_meth'
    

答案 1 :(得分:9)

这是更实用的答案。

很少重要

  1. What is a metaclass in Python”。底线type是所有类的元类。你几乎没有实际用途。

    class X(object):
        pass
    type(X) == type
    
  2. What are your (concrete) use cases for metaclasses in Python?”。底线。无。

  3. Python's Super is nifty, but you can't use it”。有趣的是,但实用价值不大。您永远不需要解析复杂的多继承网络。通过使用明确的策略设计而不是多重继承,可以轻松防止出现此问题。

  4. 这是我在过去7年的Python编程方面的经验。

    1. 一个班级有一个或多个超类,形成一个从我班级到object的简单链。

    2. “class”的概念由名为type的元类定义。我可能想扩展“阶级”的概念,但到目前为止,它从未在实践中出现过。不止一次。 type始终做正确的事。

    3. 在实践中使用super非常有效。它允许子类遵循它的超类。它恰好出现在这些元类示例中,因为它们扩展了内置元类type

      但是,在所有子类情况下,您将使用super来扩展超类。

    4. <强>元类

      元类问题是:

      • 每个对象都引用了它的类型定义或“类”。

      • class本身也是一个对象。

      • 因此class类型的对象引用了它的类型或“类”。 “类”的“类”是元类。

      由于“class”不是C ++运行时对象,因此在C ++中不会发生这种情况。它确实发生在Java,Smalltalk和Python中。

      元类定义了类对象的行为。

      • 您与班级互动的90%是要求班级创建新对象。

      • 10%的情况下,您将使用类方法或类变量(C ++或Java用语中的“静态”。)

      我找到了一些用于类级方法的用例。我几乎没有类变量的用例。我从来没有改变对象构建方式的情况。