`__new__`中的`super()`是什么意思

23 投票
4 回答
20148 浏览
提问于 2025-04-17 11:54

注意:这是一个使用Python实现享元模式的部分内容

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__的说明:

构造函数叫做__new__,而不是__init__,它只接受一个参数,就是正在被构造的类(在对象被构造之前调用,所以没有self这个参数)。它还必须返回新创建的对象。

4 个回答

1

我觉得你是在用Python3,在这个版本中,使用super的时候不需要写上当前类的名字。super指的是当前类的父类,它会帮你正确地找到方法的调用顺序,这样你就能从正确的父类中调用方法了。__new__是一个用来创建实例的方法。它是创建实例的第一步。

5

super() 是用来引用父类的,也就是你从中继承的那个类。

__new__ 是一个方法,用来创建这个类的新实例,如果这个方法被定义了的话。

36

首先,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"))时,会经过以下几个步骤:

  1. 如果"A"O的实例字典中(O.__dict__)有定义,那么就直接返回这个值。
  2. 如果没有,就会依次检查O的类继承顺序中的每个类,看看它们的字典里有没有"A"。如果找到了,就把这个值叫做D
  3. 如果D没有定义__get__,那么就直接返回它。如果有定义,那么D就被称为“描述符”,并且会调用它的__get__方法,传入O作为第一个参数,type(O)作为第二个参数。

在类上引用属性的过程差不多,只是把实例换成了类,具体的不同在于:

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

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

super(T, O)创建的超级对象,是一个(内置的)对象,它有一个__getattribute__方法,这个方法会在每次引用属性时被调用,并在O的类继承顺序中,查找仅在T之后的类的字典。找到的值会像往常一样调用__get__

这个过程有点复杂,下面用你的具体例子来说明一下。因为CarModel是这样定义的,它的类继承顺序是[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的类继承顺序中,后面的类,发现"__new__"object类的字典中。这个值是一个静态方法,它有一个__get__方法,这个方法会用Nonecls作为参数调用。因为__new__是静态方法,所以它的__get__方法会直接返回这个函数,不做任何修改。因此,super(CarModel, cls).__new__object.__new__是完全一样的。
  5. 最后一步得到的函数(也就是object.__new__)会用cls参数调用,这里的cls可能是CarModel,最终创建一个CarModel类的新实例。

希望这些解释能让你有所理解。

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

撰写回答