【问题标题】:"MetaClass", "__new__", "cls" and "super" - what is the mechanism exactly?“MetaClass”、“__new__”、“cls”和“super”——具体的机制是什么?
【发布时间】:2010-09-28 14:25:16
【问题描述】:

我读过这样的帖子:

  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

但不知何故,我感到困惑。许多困惑,例如:

我何时以及为什么必须执行以下操作?

# 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), {})

super 究竟是如何工作的?

什么是链接 1 中的类注册和取消注册,它是如何工作的? (我认为这与singleton 有关。我可能是错的,来自C 背景。我的编码风格仍然是函数式和OO 的混合体。

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

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

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

P.S.:我把最后一部分写成代码是因为 StackOverflow 格式正在转换文本 metaclass->__new__ 到元类->

【问题讨论】:

    标签: python types metaclass super


    【解决方案1】:

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

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

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

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

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

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

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

    在你给出的例子中,发生了什么:

    1. 正在拨打__new__ 冒泡到下一件事 维修保养在这种情况下,super(MyType, cls) 将解析为 type; 调用 type.__new__ 让 Python 完成它的正常实例 创建步骤。

    2. 此示例使用元类 强制执行单例。他是 覆盖 __call__ 在 元类,这样每当一个类 创建实例,他拦截 那,并且可以绕过实例 如果已经有一个,则创建 (存储在cls.instance)。笔记 覆盖 __new__ 在 元类还不够好​​, 因为那只在什么时候被调用 创建。覆盖 __new__ 在课堂上会起作用, 但是。

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

    我不确定您要查找的是哪种代码示例,但这里有一个简短的示例,展示了元类、继承和方法解析:

    print('>>> # Defining classes:')
    
    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(metaclass=MyMeta):
        def __init__(self):
            super(A, self).__init__()
            print("A init")
    
        def meth(self):
            print("A.meth")
    
    class B(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")
    
    print('>>> c_obj = C()')
    c_obj = C()
    print('>>> c_obj.meth()')
    c_obj.meth()
    print('>>> C.meta_meth()')
    C.meta_meth()
    print('>>> c_obj.meta_meth()')
    c_obj.meta_meth()
    

    示例输出(使用 Python >= 3.6):

    >>> # Defining classes:
    meta: creating A ()
    meta: creating B ()
    meta: creating C (A, B)
    >>> c_obj = C()
    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 "metatest.py", line 41, in <module>
        c_obj.meta_meth()
    AttributeError: 'C' object has no attribute 'meta_meth'
    

    【讨论】:

    • 谢谢。 Registry 和 MetaSingleton - 只是链接中的一些名称(stackoverflow.com/questions/100003/… 提到,上下文在代码中。这并不能回答所有问题,我将等待更多答案,然后再回复任何问题。
    • 啊,我明白了——我不明白#first 链接和#second 链接cmets 是什么意思。我已经为示例添加了解释,现在我可以在上下文中看到它们。
    • 再次感谢。我已经编辑了我的问题以明确链接引用。
    • type.__new__(cls, name, bases, dct):什么是namebasesdct
    【解决方案2】:

    这是更务实的答案。

    这并不重要

    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”。有趣的笔记,但实用价值不大。您永远不需要解决复杂的多重继承网络。通过使用明确的策略设计而不是多重继承,很容易防止出现此问题。

    这是我过去 7 年的 Python 编程经验。

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

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

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

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

    元类

    元类问题是这样的:

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

    • class 本身也是一个对象。

    • 因此,class 类型的对象具有对其类型或“类”的引用。 “类”的“类”是元类。

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

    元类定义类对象的行为。

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

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

    我发现了一些类级方法的用例。我几乎没有类变量的用例。我从来没有改变过对象构造的工作方式。

    【讨论】:

    • 关于多重继承,我不同意。一个简单的单机链到对象是很好的设计 IMO,但混音很棒,我鼓励在适当的时候使用它们。一旦你使用混音,你确实需要了解 MRO 以确保你不会在脚下开枪。
    • @S.Lott:我认为对 MRO 和 super 的深入了解是一个非常有价值的工具。如果没有意识到多重继承可能给您带来的讨厌,我们就不会知道为什么线性继承链、简单的混合等是可取的。知道错误的选项仍然有用!
    • @S.Lott:1.“它很少有关系”——你能引出罕见的案例吗 2.“它们必须被深入理解吗?”——为什么不呢?至少出于好奇心的一部分,即使一个人只能找到少数几个用例。 3.我同意其中的策略设计部分,但我想使用 MRO 作为交叉检查很好。
    • 他的意思是我们都是羊,需要排队。别担心,你不需要知道这一点。这对你来说太难了。 知道的越多,他的工作就越不安全。 搞砸。尽可能多地了解你使用的语言,不要让这些 (python) 灌输者告诉你你需要知道什么。和平。
    • @hiwaylon:“所有的羊都需要排队”?真的吗?我以为我说它很少需要。 “尽可能多地了解您使用的语言”。我不是建议专门以 Django 为例吗?为什么这么生气?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-11-12
    • 1970-01-01
    • 2014-03-01
    • 2021-11-23
    • 2011-07-17
    • 2011-09-08
    • 1970-01-01
    相关资源
    最近更新 更多