class DahlBookManager(models.Manager):
def get_query_set(self):
return super(DahlBookManager, self).get_query_set().filter(author='Roald Dahl')
这段自定义模型manager的代码里面 用super(DahlBookManager, self)这样的方式构造一个父类对象为什么要传一个DahlBookManager类名和self引用啊? DahlBookManager这个作为参数准确的说是一个DahlBookManager的对象吧? 也就是想问这个构造父类对象的super方法中为什么要传入这样两个参数?
也许可以认为这是Python设计的缺陷导致的,因为Python 3.0只需要用
super().some_attr
就行了。至于为什么需要两个参数,可以大概分析一下,如果有错,欢迎指正。先介绍下背景知识:super是从Python 2.2开始随着
new-style class
一起引入的,也只能应用于所谓的new-style class
(即直接或间接继承于object
的class),可以在一定程度上解决所谓钻石继承
的问题。2.2起所有python内置class都是new-style class。那么super是什么呢?实际上它是一个builtin的type,你调用
super(Base, self)
会返回一个__class__ = super
的对象,这个对象可以作为一个代理,通过BFS的顺序(实际上列表已经保存在Base.__mro__
里了)去访问第一个直接定义了目标属性的基类里的属性。super(type, obj_or_subtype).attr
基本上可以认为是find_in_mro_provide_by(obj_or_subtype, "attr")
,有点晦涩。注意,super()返回的不是“父类对象”,而是一个super类型的对象;实例化的时候,第一个参数是一个类型(type),第二个参数可以是type的instance,也可以是type的subclass。这两点题主都理解错了。
介绍完基础知识,可以先说说为什么要有第二个参数。理由很简单 —— 我们知道 self 代表当前对象,每个对象的方法在定义的时候都需要显示地把self作为第一个参数,你本来应该写成这样
但是因为Python语法允许
obj.some_metod(*args, **kwargs)
(本质上是个语法糖) ,所以你可以写得简单点(不必显式地给出方法的第一个参数)。而super对象则不同,它没有语法上的直接支持,所以在内部invoke some_method的时候必须指定某个对象,而这个对象的得你自己塞给它,也就是说把这个super对象绑定(bound)到第二个参数上。所以实际上并不是非要用self作为super的第二个参数,甚至super并不是必须在class内部才能调用:至于为什么要有第一个参数,如果你看了
help(super)
就会发现它居然提供了个单参数的版本:这个理解起来比较困难点。先说这个
unbound
,没绑定,就是说这个super对象没有实际绑定到某个对象上,它并不是可以直接用的。要怎么用呢?那就得注意到help(super)
里面有一个__get__
方法,也就是说,super类还是一个Descriptor类!哎,这个Descriptor类展开又是好大一段,简单地说就是它可以把自己和某个object的属性绑定,使得访问这个属性的时候,实际上是在调用它的__get__/__set__
方法:回到unbound super, 为了使用它,就要通过 get 方法把它再绑定到一个对象上。由于Descriptor的属性,特别适合这么用:
这是它的一个可能用法。我不确定是否还有其他更合适的用途,但是在这里实际上也并不是很好,尤其是遇到staticmethod的时候还会出错,再加上绕了这么大一个弯,实在不是很推荐使用。
据说unbound super的使用非常少,不知道现实意义有多少,也不知道当初为什么设计成这个样子,总之由于Python3.0已经改了(虽然仍然保留了unbound super),所以基本上还是可以认为这是设计的历史遗留问题。
参考文献(unbound super主要参考了这个系列):Things to Know About Python Super
[1] http://www.artima.com/weblogs/viewpost.jsp?thread=236275
[2] http://www.artima.com/weblogs/viewpost.jsp?thread=236278
[3] http://www.artima.com/weblogs/viewpost.jsp?thread=237121