关于python:`__new__`中的”super()”是什么?_`

what does `super()` in `__new__`

注意:使用python的flyweight实现的一部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import weakref

class CarModel:
    _models = weakref.WeakValueDictionary()

    def __new__(cls, model_name, *args, **kwargs):
        model = cls._models.get(model_name)
        if not model:
            model = super().__new__(cls)
            cls._models[model_name] = model    
        return model

    def __init__(self, model_name, air=False):
        if not hasattr(self,"initted"):
          self.model_name = model_name
          self.air = air
          self.initted=True

问题1>super()是什么意思?是指CarModel的父类吗?

问题2>我也很难理解__new__的功能是如何工作的?具体来说,下面的一行。

1
model = super().__new__(cls)

__new__说明:

The constructor function is called __new__ as opposed to __init__, and
accepts exactly one argument, the class that is being constructed (it
is called before the object is constructed, so there is no self
argument). It also has to return the newly created object.


super()开始,它本身就是super(A, B)的简写,其中A是代码发生的类,B是代码发生的函数的第一个参数;因此在您的特定情况下,super().__new__(cls)扩展到super(CarModel, cls).__new__(cls)

反过来,super(T, O)返回一个"超级对象"。要了解超级对象的功能,您需要了解实例和类上的属性引用如何在Python中工作。

假设不涉及__getattr____getattribute__方法,则参考对象O上的属性A(即,评估O.Agetattr(O,"A")通过以下步骤进行:

  • 如果"A"是在O的实例dict(O.__dict__中定义的,则直接返回该dict上的值,与实际值完全相同。
  • 否则,依次检查O的方法解析顺序中的每个类,在每个dict中查找"A"。如果找到,调用值D
  • 如果D没有定义__get__,则返回原样。但是,如果是这样,那么D被称为"描述符",它的__get__方法是以O作为第一个参数调用的,type(O)作为第二个参数调用的。
  • 类上的属性引用的工作原理大致相同,将作为引用的类替换为实例,但有以下区别:

    • 步骤1不适用。
    • 调用__get__方法时,None作为第一个参数,类作为第二个参数被引用。

    Python使用描述符来实现实例方法、类方法、静态方法和属性等。

    那么,用super(T, O)创建的超级对象就是一个(内置的)对象,它有一个__getattribute__方法,对其上的每个属性引用都进行调用,并在O的mro中,在t后面的唯一类的dicts中查找属性。然后它找到的值,它像往常一样调用__get__

    这个过程有点复杂,所以作为一个例子,这里介绍它如何处理您的特定案例。由于CarModel是按原样定义的,其mro是[CarModel, object]

  • 如上所述,super().__new__(cls)扩展到super(CarModel, cls).__new__(cls)
  • 评估super(CarModel, cls)生成超级对象S
  • python在S上获取属性"__new__"(相当于在python代码中调用getattr(S,"__new__"))。
  • 由于S是在CarModel类上创建的,所以在CarModel的MRO中考虑了CarModel之后的类,并在object类的dict中找到了"__new__"。它的值是静态方法,它有一个__get__方法,使用参数Nonecls调用该方法。由于__new__是一个静态方法,其__get__方法只是返回未修改的函数。因此,super(CarModel, cls).__new__object.__new__完全相同。
  • 最后一步得到的函数(即object.__new__cls参数调用,其中cls可能是CarModel,最后是CarModel类的一个新实例。
  • 我希望这完全可以理解。

    (为了完整起见,应该指出,object类上的实际__new__函数实际上不是一种静态方法,而是一种特殊的内置函数,它根本没有__get__方法,但是由于__get__方法对静态方法只是返回了定义它们的函数,其效果是是一样的。)


    super()用于引用超类(即从中进行子类化的父类)。

    __new__是一个方法,如果定义了该类,它将被调用来创建该类的新实例。


    我相信,您使用的是python3,其中super不需要提供相同的类名。super引用当前类的基类,并执行正确的方法解析顺序,以便您从正确的基类调用该方法。__new__是用来创建实例的方法。这是创建实例的第一步。