注意:使用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.
- @Ben根据该文档,__new__()返回cls的一个实例。为什么op中的代码model = super().__new__(cls) 可以创建cls的实例?CarModel的超级类如何知道如何创建其子类的实例?
- 这将是一个非常好的问题(如果还没有被问到的话)。简短的回答是,您正在使用cls参数将当前类传递给它。最后,如果不一直推迟到object.__new__,就无法实际创建新实例,因为python没有"分配实例"的指令。但是object.__new__知道创建一个它所通过的类的实例(它也将是object的实例,因为所有东西都是object的实例)。
从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的实例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__方法,使用参数None和cls调用该方法。由于__new__是一个静态方法,其__get__方法只是返回未修改的函数。因此,super(CarModel, cls).__new__与object.__new__完全相同。
最后一步得到的函数(即object.__new__用cls参数调用,其中cls可能是CarModel,最后是CarModel类的一个新实例。
我希望这完全可以理解。
(为了完整起见,应该指出,object类上的实际__new__函数实际上不是一种静态方法,而是一种特殊的内置函数,它根本没有__get__方法,但是由于__get__方法对静态方法只是返回了定义它们的函数,其效果是是一样的。)
- 在super(class1, class2)中,super如何使用class1和class2?
- @阿德里安:我想我不明白你的问题,因为这听起来像是整个答案的意思。有什么特别的地方吗?
super()用于引用超类(即从中进行子类化的父类)。
__new__是一个方法,如果定义了该类,它将被调用来创建该类的新实例。
- 在super(class1, class2)中,super如何使用class1和class2?
我相信,您使用的是python3,其中super不需要提供相同的类名。super引用当前类的基类,并执行正确的方法解析顺序,以便您从正确的基类调用该方法。__new__是用来创建实例的方法。这是创建实例的第一步。
- 在super(class1, class2)中,super如何使用class1和class2?