`__new__`中的`super()`是什么意思
注意:这是一个使用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 个回答
我觉得你是在用Python3,在这个版本中,使用super的时候不需要写上当前类的名字。super指的是当前类的父类,它会帮你正确地找到方法的调用顺序,这样你就能从正确的父类中调用方法了。__new__
是一个用来创建实例的方法。它是创建实例的第一步。
super()
是用来引用父类的,也就是你从中继承的那个类。
__new__
是一个方法,用来创建这个类的新实例,如果这个方法被定义了的话。
首先,super()
其实就是super(A, B)
的简写,其中A
是代码所在的类,B
是代码所在函数的第一个参数;所以在你的例子中,super().__new__(cls)
可以展开为super(CarModel, cls).__new__(cls)
。
接下来,super(T, O)
会返回一个“超级对象”。要理解这个超级对象的作用,你需要明白在Python中,如何访问实例和类的属性。
假设没有使用__getattr__
或__getattribute__
这些方法,当你在对象O
上引用属性A
(也就是执行O.A
或getattr(O, "A")
)时,会经过以下几个步骤:
- 如果
"A"
在O
的实例字典中(O.__dict__
)有定义,那么就直接返回这个值。 - 如果没有,就会依次检查
O
的类继承顺序中的每个类,看看它们的字典里有没有"A"
。如果找到了,就把这个值叫做D
。 - 如果
D
没有定义__get__
,那么就直接返回它。如果有定义,那么D
就被称为“描述符”,并且会调用它的__get__
方法,传入O
作为第一个参数,type(O)
作为第二个参数。
在类上引用属性的过程差不多,只是把实例换成了类,具体的不同在于:
- 第一步不适用。
__get__
方法的第一个参数是None
,第二个参数是被引用的类。
Python使用描述符来实现实例方法、类方法、静态方法和属性等功能。
用super(T, O)
创建的超级对象,是一个(内置的)对象,它有一个__getattribute__
方法,这个方法会在每次引用属性时被调用,并在O
的类继承顺序中,查找仅在T之后的类的字典。找到的值会像往常一样调用__get__
。
这个过程有点复杂,下面用你的具体例子来说明一下。因为CarModel
是这样定义的,它的类继承顺序是[CarModel, object]
。
super().__new__(cls)
展开为super(CarModel, cls).__new__(cls)
,如上所述。super(CarModel, cls)
被计算,得到一个超级对象S
。- Python在
S
上获取属性"__new__"
(相当于在Python代码中调用getattr(S, "__new__")
)。 - 由于
S
是在CarModel
类上创建的,它会查看CarModel
的类继承顺序中,后面的类,发现"__new__"
在object
类的字典中。这个值是一个静态方法,它有一个__get__
方法,这个方法会用None
和cls
作为参数调用。因为__new__
是静态方法,所以它的__get__
方法会直接返回这个函数,不做任何修改。因此,super(CarModel, cls).__new__
和object.__new__
是完全一样的。 - 最后一步得到的函数(也就是
object.__new__
)会用cls
参数调用,这里的cls
可能是CarModel
,最终创建一个CarModel
类的新实例。
希望这些解释能让你有所理解。
(为了完整性,值得一提的是,object
类的实际__new__
函数并不是静态方法,而是一个特殊的内置函数,它根本没有__get__
方法,但由于静态方法的__get__
方法只是返回它们定义时的函数,所以效果是一样的。)