关于python:“MetaClass”,“__ new__”,“cls”和“super” – 究竟是什么机制?

“MetaClass”, “__new__”, “cls” and “super” - what is the mechanism exactly?

我读过这样的文章:

  • 什么是Python中的元类?
  • 在Python中,元类的(具体)用例是什么?
  • Python的超棒很漂亮,但你不能用它
  • 但不知怎么的,我搞糊涂了。许多困惑,如:

    什么时候,为什么我要做如下的事情?

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

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

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

    超级如何工作?

    什么是Link1中的类注册和注销,它是如何工作的?(我想这和辛格尔顿有关。我可能错了,因为我是C背景的。我的编码风格仍然混合了函数和OO)。

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

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

    )使用注释良好的工作代码(尽管第一个链接非常接近,但它不讨论cls关键字、super(..)和注册表)。最好是具有多重继承的示例。

    P.S.:我把最后一部分作为代码,因为堆栈溢出格式正在转换文本metaclass->__new__。到元类->新建


    好吧,你已经在这里的混合中加入了很多概念!我将提出一些具体的问题。

    一般来说,理解super、mro和metclasses会变得更加复杂,因为在过去几个版本的python中,这个棘手的领域发生了很多变化。

    python自己的文档是一个非常好的参考,并且完全是最新的。有一篇IBMdeveloperWorks文章可以作为一个介绍,它采用了一种更基于教程的方法,但是请注意,它已经有5年的历史了,并且花了很多时间讨论元类的老式方法。

    super是如何访问对象的超级类的。它比(例如)Java的EDCOX1的0个关键字复杂得多,主要是因为Python中有多个继承。正如"超级有害"解释的那样,使用super()会导致隐式使用一系列超级类,其顺序由方法解析顺序(mro)定义。

    通过在类上(而不是在实例上)调用mro(),可以很容易地看到类的mro。注意,元类不在对象的超级类层次结构中。

    托马斯对元类的描述非常好:

    A metaclass is the class of a class.
    Like a class defines how an instance
    of the class behaves, a metaclass
    defines how a class behaves. A class
    is an instance of a metaclass.

    在您给出的示例中,发生了以下情况:

  • __new__的呼叫正在冒泡到下一件事MRO。在这种情况下,super(MyType,
    cls)
    将向type作出决议;调用type.__new__让python完成这是正常情况创建步骤。

  • 这个例子使用的是元类执行一个单例。他是在元类,这样每当一个类实例被创建,他截取可以绕过实例如果已经存在,则创建(存储在cls.instance中)。注释在元类还不够好,因为只有在创建类。覆盖__new__在班上会有用的,然而。

  • 这显示了一种动态创建一个类。他来了附加提供的类的名称创建的类名,以及将其添加到类层次结构也是。

  • 我不确定您要找的是哪种类型的代码示例,但下面是一个简短的示例,其中显示了元类、继承和方法解析:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    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'


    下面是更务实的答案。

    它很少重要

  • "什么是Python中的元类"。底线是,type是所有类的元类。你几乎没有实际的用处。

    1
    2
    3
    class X(object):
        pass
    type(X) == type
  • "Python中元类的(具体)用例是什么?".底线。一个也没有。

  • "Python的超棒很漂亮,但你不能用它"。有趣的注释,但实用价值不大。您永远不需要解决复杂的多继承网络。使用一个明确的策略设计而不是多个继承很容易避免这个问题的发生。

  • 下面是我在过去7年的Python编程中的经验。

  • 一个类有一个或多个超类,形成从我的类到object的简单链。

  • "类"的概念是由名为type的元类定义的。我可能想扩展"类"的概念,但到目前为止,它还没有在实践中出现。不是一次。type总是做正确的事情。

  • 使用super在实践中效果很好。它允许子类遵从它的超类。它恰巧出现在这些元类示例中,因为它们扩展了内置的元类type

    然而,在所有子类情况下,您将使用super来扩展一个超类。

  • 元类

    元类的问题是:

    • 每个对象都有一个对其类型定义的引用,或"类"。

    • class本身也是一个对象。

    • 因此,class类型的对象引用了它的类型或"类"。"class"的"class"是一个元类。

    因为"类"不是C++运行时对象,这在C++中是不存在的。它确实发生在爪哇,SimultTalk和Python。

    元类定义类对象的行为。

    • 90%的与类的交互是要求类创建一个新对象。

    • 10%的时间,你将使用类方法或类变量(C++中的静态)或Java语言。

    我发现了一些类级方法的用例。我几乎没有类变量的用例。我从未有过改变物体构造工作方式的情况。