`__new__` 中的 `super()` 是什么 [英] what does `super()` in `__new__`

查看:95
本文介绍了`__new__` 中的 `super()` 是什么的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

注意:使用 Python 实现的享元实现的一部分

import weakref类 CarModel:_models = weakref.WeakValueDictionary()def __new__(cls, model_name, *args, **kwargs):模型 = cls._models.get(model_name)如果不是模型:模型 = super().__new__(cls)cls._models[model_name] = 模型回报模式def __init__(self, model_name, air=False):如果不是 hasattr(self, "initted"):self.model_name = 模型名self.air = 空气self.initted=真

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

问题 2> 我也很难理解函数 __new__ 是如何工作的?具体来说,下面这行.

model = super().__new__(cls)

__new__ 的描述:

<块引用>

构造函数被称为 __new__ 而不是 __init__,并且只接受一个参数,即正在构造的类(它在构造对象之前被调用,所以没有 self争论).它还必须返回新创建的对象.

解决方案

super() 开头本身就是 super(A, B) 的简写,其中A是代码所在的类,B是代码所在函数的第一个参数;所以在你的特定情况下,super().__new__(cls) 扩展为 super(CarModel, cls).__new__(cls).

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

假设不涉及__getattr____getattribute__ 方法,引用对象O 上的属性A(即,评估 OAgetattr(O, "A")) 执行以下步骤:

  1. 如果在 O 的实例字典 (O.__dict__) 中定义了 "A",则返回该字典上的值直接,准确地原样.
  2. 否则,依次检查 O 方法解析顺序中的每个类,在它们的每个 dict 中查找 "A".如果找到,则调用值 D.
  3. 如果 D 又没有定义 __get__,那么它会原样返回.但是,如果是,则 D 被称为描述符",它的 __get__ 方法被调用,O 作为第一个参数, 和 type(O) 作为第二个参数.

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

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

Python 使用描述符来实现诸如实例方法、类方法、静态方法和属性之类的东西.

使用 super(T, O) 创建的超级对象是一个(内置)对象,带有 __getattribute__ 方法,该方法在每个属性引用上调用在它上面,并在 O 的 MRO 中 T 之后的 only 类的字典中查找属性.然后它找到的值,它像往常一样调用 __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 类本身的字典中找到 "__new__" .它的值是一个静态方法,有一个 __get__ 方法,该方法使用参数 Nonecls 调用.由于 __new__ 是一个静态方法,它的 __get__ 方法简单地返回函数原样,未经修改.因此,super(CarModel, cls).__new__object.__new__ 完全相同.
  5. 上一步得到的函数(即object.__new__)用cls参数调用,其中cls可能是CarModel,最后是 CarModel 类的新实例.

我希望这完全可以理解.

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

Note: Part of a flyweight implementation with 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

Question 1> what does super() mean? Does it mean the parent class of CarModel?

Question 2> I also have difficulties to understand the how the function __new__ works? Specifically, the following line.

model = super().__new__(cls)

Description for __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.

解决方案

To begin with super() in itself is simply shorthand for super(A, B), where A is the class wherein the code occurs, and B is the first argument to the function in which the code occurs; so in your particular case, super().__new__(cls) expands to super(CarModel, cls).__new__(cls).

In turn, super(T, O) returns a "super object". To understand what a super object does, you need to understand how attribute references on instances and classes work in Python.

Assuming no __getattr__ or __getattribute__ methods are involved, referencing attribute A on an object O (that is, evaluating O.A or getattr(O, "A")) proceeds through the following steps:

  1. If "A" is defined in O's instance dict (O.__dict__), then the value on that dict is returned directly, precisely as it is.
  2. Otherwise, each of the classes in O's method resolution order are checked in turn, looking for "A" in each of their dicts. If found, call the value D.
  3. If D, in turn, does not define a __get__, then it is returned as it is. If it does, however, then D is referred to as a "descriptor", and its __get__ method is called with O as the first argument, and type(O) as the second argument.

An attribute reference on a class works about the same, substituting the class being reference for the instance, with the following differences:

  • Step 1 doesn't apply.
  • The __get__ method is called with None as the first argument, and the class being referenced as the second.

Python uses descriptors to implement such things as instance methods, class methods, static methods, and properties.

A super object created with super(T, O), then, is a (built-in) object with a __getattribute__ method which is called on every attribute reference on it, and looks up the attribute in the dicts of the only classes following T in O's MRO. The value it then finds, it calls __get__ on as usual.

The process is a bit complex, so as an example, here's how it would work on your specific case. Since CarModel is defined as it is, its MRO is [CarModel, object].

  1. super().__new__(cls) expands to super(CarModel, cls).__new__(cls), as described above.
  2. super(CarModel, cls) is evaluated to yield a super object S.
  3. Python fetches the attribute "__new__" on S (the equivalent of calling getattr(S, "__new__") in Python code).
  4. Since S was created on the CarModel class, it considers the classes following CarModel in the MRO of CarModel, and finds "__new__" in the dict of the object class itself. Its value, a static method, has a __get__ method, which is called with the arguments None and cls. Since __new__ is a static method, its __get__ method simply returns the function as it is, unmodified. Therefore, super(CarModel, cls).__new__ is precisely the same as object.__new__.
  5. The function obtained in the last step (that is, object.__new__) is called with the cls argument, where cls is probably CarModel, finally a new instance of the CarModel class.

I hope that was at all understandable.

(For the sake of completeness, it should be mentioned that the actual __new__ function on the object class is not actually a static method, but a special built-in function that simply has no __get__ method at all, but since the __get__ method on static methods just return the function they were defined with, the effect is the same.)

这篇关于`__new__` 中的 `super()` 是什么的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆