`__new__`中的`super()`是什么?

时间:2012-01-29 21:26:29

标签: python python-3.x

注意:使用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__的说明:

  

构造函数调用__new__而不是__init__,和。{   只接受一个参数,正在构造的类(它   在构造对象之前调用,因此没有自我   参数)。它还必须返回新创建的对象。

4 个答案:

答案 0 :(得分:14)

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

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

假设不涉及__getattr____getattribute__方法,请在对象A上引用属性O(即评估O.A或{{1} })继续执行以下步骤:

  1. 如果在getattr(O, "A")的实例dict("A")中定义了O,那么该dict上的值将直接返回,就像它一样。
  2. 否则,依次检查O.__dict__方法解析顺序中的每个类,在每个单词中查找O。如果找到,请调用值"A"
  3. 如果D反过来没有定义D,那么它会按原样返回。但是,如果确实如此,那么__get__被称为“描述符”,其D方法被调用,__get__作为第一个参数,O作为第二个论点。
  4. 类的属性引用大致相同,用实例引用的类替换,但有以下区别:

    • 第1步不适用。
    • 调用type(O)方法时,__get__作为第一个参数,而类被引用为第二个参数。

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

    然后,使用None创建的超级对象是一个(内置)对象,其中包含super(T, O)方法,并在其上的每个属性引用上调用,并在dicts中查找属性在__getattribute__的MRO中,只有在T 之后的类。它随后找到的值,它会像往常一样调用O

    这个过程有点复杂,举个例子,这就是它如何适用于你的特定情况。由于__get__按其定义,因此其MRO为CarModel

    1. [CarModel, object]扩展为super().__new__(cls),如上所述。
    2. 评估
    3. super(CarModel, cls).__new__(cls)以产生超级对象super(CarModel, cls)
    4. Python在S上获取属性"__new__"(相当于在Python代码中调用S)。
    5. getattr(S, "__new__")类创建S以来,它会在CarModel的MRO中考虑CarModel后面的类,并在字典中找到CarModel "__new__"类本身。它的值是一个静态方法,它有一个object方法,使用参数__get__None调用。由于cls是一个静态方法,因此它的__new__方法只是原封不动地返回函数。因此,__get__super(CarModel, cls).__new__完全相同。
    6. 使用object.__new__参数调用最后一步中获得的函数(即object.__new__),其中cls可能是cls,最后是一个新实例CarModel班。
    7. 我希望这完全可以理解。

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

答案 1 :(得分:4)

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

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

答案 2 :(得分:1)

我相信,你使用的是Python3,其中super不需要提供相同的类名。 Super指的是当前类的Base类,并为您从正确的基类调用方法做了正确的Method Resolution Order__new__是调用以创建实例的方法。这是first step in the instance creation

答案 3 :(得分:0)

我认为这个答案的一部分对 __new____init__ 之间的关系感到困惑。我自己对此感到困惑。以下是如何回答此类问题。

<块引用>

在我们开始之前,请务必注意,定义 __new__ 始终应用一个不可见/神奇的 @classmethod 装饰器。

from inspect import signature # find function signature

class JustInit(object):
  def __init__(self, a):
    self.a = a

print("JustInit")
print(signature(JustInit.__new__))
print(signature(JustInit.__init__))
<块引用>
JustInit
(*args, **kwargs)
(self, a, b)

好吧,那没有帮助。按照@Dolda2000

的建议,让我们通过打印它们并使用 *args 传递它们来检查那些 **kwargssuper
class PrintNew(object):
  def __new__(cls, *args, **kwargs):
    print("new args:", args, "new kwargs:", kwargs)
    return super().__new__(cls, *args, **kwargs)

  def __init__(self, a):
    self.a = a

print("PrintNew")
print(signature(PrintNew.__new__))
print(signature(PrintNew.__init__))

pnew = PrintNew(42)
print(pnew.a)

结果:

<块引用>
PrintNew
(cls, *args, **kwargs)
(self, a)
new args: (42,) new kwargs: {}
Traceback (most recent call last):
  File "/home/rett/notes/python/super_new.py", line 21, in <module>
    pnew = PrintNew(42)
  File "/home/rett/notes/python/super_new.py", line 12, in __new__
    return super().__new__(cls, *args, **kwargs)
TypeError: object.__new__() takes exactly one argument (the type to instantiate)

等等...我以为new的签名是*args, **kwargs...哦,*args must really be just the cls

虽然这是真的,但需要指出的是:

  1. object 只需要 cls 变量(实际上并不需要 *args/**kwargs
  2. 您对 __new__ 的实现可以接受传递给您的 __init__ 的任何值,并且对它们进行任何您想做的事情
  3. 似乎 __new__ 返回一个未实例化的类,然后在其上调用 __init__

有了这些理论,让我们再试一次,用 return super().__new__(cls, *args, **kwargs) 替换 return super().__new__(cls)

它现在按预期运行:

<块引用>
PrintNew
(cls, *args, **kwargs)
(self, a)
new args: (42,) new kwargs: {}
42

这可能会给您一些关于如何实施的想法。