'在__new__中,`super()`是什么?'

2024-04-28 11:35:36 发布

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

注意:Python的flyweight实现的一部分

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__是如何工作的?具体来说,下面这一行。

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.


Tags: thenameselfnewmodelifismodels
3条回答

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

__new__是一个调用的方法,用于创建类的新实例(如果已定义)。

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

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

假设不涉及__getattr____getattribute__方法,则在对象O(即,计算O.Agetattr(O, "A"))上引用属性A将通过以下步骤进行:

  1. 如果"A"是在O的实例dict(O.__dict__)中定义的,则直接返回dict上的值,与实际值完全相同。
  2. 否则,依次检查O方法解析顺序中的每个类,在它们的每个dict中查找"A"。如果找到,调用值D
  3. 如果D没有定义__get__,则返回原样。但是,如果它这样做了,那么D被称为“描述符”,它的__get__方法被调用,第一个参数是O,第二个参数是type(O)

类上的属性引用的工作原理大致相同,将引用的类替换为实例,但有以下区别:

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

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

然后,使用super(T, O)创建的超级对象是一个(内置的)对象,其上的每个属性引用都调用了__getattribute__方法,并在O的MRO中的T后面的类的指令中查找该属性。然后它找到的值,像往常一样调用__get__

这个过程有点复杂,因此作为一个例子,下面是它如何处理您的特定案例。因为CarModel是按原样定义的,所以它的MRO是[CarModel, object]

  1. super().__new__(cls)展开为super(CarModel, cls).__new__(cls),如上所述。
  2. super(CarModel, cls)被求值以产生一个超级对象S
  3. Python在S上获取属性"__new__"(相当于在Python代码中调用getattr(S, "__new__"))。
  4. 由于S是在CarModel类上创建的,它考虑CarModel的MRO中CarModel之后的类,并在object类本身的dict中找到"__new__"。它的值是一个静态方法,它有一个__get__方法,用参数Nonecls调用。因为__new__是一个静态方法,所以它的__get__方法只返回未经修改的函数。因此,super(CarModel, cls).__new__object.__new__完全相同。
  5. 最后一步(即object.__new__)中获得的函数用cls参数调用,其中cls可能是CarModel,最后是CarModel类的新实例。

我希望这完全可以理解。

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

我相信,您使用的是Python3,其中不需要为super提供相同的类名。Super引用当前类的基类,并执行正确的Method Resolution Order以从正确的基类调用方法。__new__是调用以创建实例的方法。它是first step in the instance creation

相关问题 更多 >