【发布时间】:2015-07-23 06:52:31
【问题描述】:
【问题讨论】:
-
请参阅Class method differences in Python: bound, unbound and static,了解绑定或取消绑定的含义。
标签: python super python-descriptors
【问题讨论】:
标签: python super python-descriptors
Python 函数对象是descriptors,Python 使用描述符协议将函数绑定 到一个实例。这个过程产生一个绑定方法。
绑定是在您调用方法时让“神奇”self 参数出现的原因,也是在您尝试将属性用作实例的属性时让property 对象自动调用方法的原因。
super() 当你尝试使用它来查找父类上的方法时,带有两个参数的super() 会调用相同的描述符协议; super(Foo, self).bar() 将遍历Foo 父类,直到找到属性bar,如果这是一个描述符对象,它将绑定到self。调用bar 然后调用绑定方法,该方法又调用传入self 参数为bar(self) 的函数。
为此,super() 对象存储要绑定的类(第一个参数)和 self(第二个参数),和self 参数的类型作为属性分别为__thisclass__、__self__和__self_class__:
>>> class Foo:
... def bar(self):
... return 'bar on Foo'
...
>>> class Spam(Foo):
... def bar(self):
... return 'bar on Spam'
...
>>> spam = Spam()
>>> super(Spam, spam)
<super: <class 'Spam'>, <Spam object>>
>>> super(Spam, spam).__thisclass__
<class '__main__.Spam'>
>>> super(Spam, spam).__self__
<__main__.Spam object at 0x107195c10>
>>> super(Spam, spam).__self_class__
<class '__main__.Spam'>
查找属性时,搜索__self_class__属性的__mro__属性,从__thisclass__的位置后一位开始,并绑定结果。
super() 仅具有 一个 参数将其 __self__ 和 __self_class__ 属性设置为 None 并且无法进行查找尚:
>>> super(Spam)
<super: <class 'Spam'>, NULL>
>>> super(Spam).__self__ is None
True
>>> super(Spam).__self_class__ is None
True
>>> super(Spam).bar
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'super' object has no attribute 'bar'
对象确实支持描述符协议,所以你可以像绑定方法一样绑定它:
>>> super(Spam).__get__(spam, Spam)
<super: <class 'Spam'>, <Spam object>>
>>> super(Spam).__get__(spam, Spam).bar()
'bar on Foo'
这意味着您可以将这样的对象存储在一个类中,并使用它来遍历父方法:
>>> class Eggs(Spam):
... pass
...
>>> Eggs.parent = super(Eggs)
>>> eggs = Eggs()
>>> eggs.parent
<super: <class 'Eggs'>, <Eggs object>>
>>> eggs.parent.bar()
'bar on Spam'
主要用例是避免每次都使用 super() 的两个参数形式重复该类:
class Foo:
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
# class-private attribute so subclasses don’t clobber one another
setattr(cls, f'_{cls.__name__}__parent', super(cls))
def bar(self):
return 'bar on Foo'
class Spam(Foo):
def bar(self):
return 'spammed: ' + self.__parent.bar()
但是在使用类方法时会中断(因为 cls.__parent 不会绑定)并且已被 Python 3 的 super() 取代,零参数从闭包中获取类:
class Foo:
def bar(self):
return 'bar on Foo'
class Spam(Foo):
def bar(self):
return 'spammed: ' + super().bar()
【讨论】:
__mro__ attribute,然后直接访问类命名空间(例如,vars(classobject) 为您提供该命名空间,一个字典)。