“元类”、“新的”、“cls”和“super”到底是什么机制?

2024-03-28 08:48:45 发布

您现在位置:Python中文网/ 问答频道 /正文

我读过这样的帖子:

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

超级到底是怎么工作的?

什么是link1中的类注册和注销,它到底是如何工作的?(我想这和singleton有关。我可能错了,我是C背景的。我的编码风格仍然是函数式和面向对象的混合。

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

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

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

备注:我将最后一部分作为代码,因为堆栈溢出格式正在转换文本metaclass->__new__ 到元类->;新建


Tags: nameinselfnewreturnisusewhat
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. 一个类有一个或多个超类,形成从我的类到object的简单链。

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

  3. 使用super在实践中效果非常好。它允许一个子类服从它的超类。它碰巧出现在这些元类示例中,因为它们正在扩展内置元类type

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

元类

元类问题是:

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

  • class本身也是一个对象。

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

因为“类”不是C++运行时对象,所以C++中没有发生这种情况。它确实发生在Java、Smalltalk和Python中。

元类定义类对象的行为。

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

  • >P 10%,您将使用类方法或类变量(C++中的静态)或java语句。

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

好吧,你已经把一些概念混为一谈了!我要问你几个具体的问题。

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

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

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

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

Thomas元类的描述here非常好:

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.

在您给出的示例中,下面是发生的情况:

  1. 正在调用__new__ 冒泡到 先生。在这种情况下,super(MyType, cls)将解析为type; 调用type.__new__让Python 完成这是正常情况 创建步骤。

  2. 这个例子使用的是元类 强制执行一个单子。他是 重写中的__call__ 元类,以便每当类 实例被创建,他拦截 可以绕过实例 如果已经有一个 (存储在cls.instance中)。注意 在 元类不够好, 因为只有在 创建。超越 __new__在类上可以工作, 然而。

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

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

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'

相关问题 更多 >