2012-01-29 36 views
6

注:与Python什么呢`超()``中__new__`

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__,和 接受且只有一个参数,那就是被构造(它 被调用之前的对象是类构建,所以没有自我 的说法)。它也必须返回新创建的对象。

+1

@Ben,基于[文档](http://docs.python.org/py3k/reference/datamodel。html#objects-values-and-types),'__new __()'返回'cls'的一个实例。为什么OP中的代码'model = super().__ new __(cls) '可以创建'cls'的实例? CarModel的超类如何知道如何创建其子类的实例? – q0987 2012-01-30 13:06:20

+2

这将是一个伟大的SO问题(如果它还没有被问到)。简短的答案是,您将'cls'参数传递给当前类。最终没有办法实际创建一个新的实例,而不会一直回到'object .__ new__',因为Python没有“分配实例”的指令。但'object .__ new__'知道要创建它传递的类的一个实例(它也是'object'的一个实例,因为一切都是'object'的一个实例)。 – Ben 2012-01-30 23:22:21

回答

1

super()用于引用超类(即您从中继承的父类)。

__new__是一种被调用来创建该类的新实例(如果已定义)的方法。

+0

在'super(class1,class2)'中,'super'如何使用'class1'和'class2'? – Adrian 2016-07-29 18:12:46

1

我相信,你正在使用Python3,其中超级不需要提供相同的类名称。 Super指的是当前类的基类,并执行适当的Method Resolution Order,以便从正确的基类中调用该方法。 __new__是被调用来创建实例的方法。这是first step in the instance creation

+0

在'super(class1,class2)'中,'super'如何使用'class1'和'class2'? – Adrian 2016-07-29 18:12:16

11

要使用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)作为第二个参数调用。

上的类的属性的参考工作大致相同,用该实例的类为参考,但有以下区别:

  • 步骤1不适用。
  • 使用None作为第一个参数调用__get__方法,并将该类引用为第二个参数。

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

super(T, O)创建的超对象的话,就是用__getattribute__方法被称为上每一个(内置)对象的属性在其上的参考,并查找属性在下面的T的只有类的类型的字典 in O的MRO。它发现的价值,它像往常一样呼吁__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__静态方法只是返回它们定义的函数,效果是一样的。)

+0

在'super(class1,class2)'中,'super'如何使用'class1'和'class2'? – Adrian 2016-07-29 18:13:04

+0

@阿德里安:我不认为我理解你的问题,因为这听起来像整个答案是要解释。有关于它的任何特定部分? – Dolda2000 2016-07-29 18:24:08