如果你不曾被Python的内置super()函数所折服,很可能是你不知道它能够做什么,或者如何有效地使用它。
很多文章写过super(),但是很多写的是错的。此文试着在以下方面进行提高:
class LoggingDict(dict):
def __setitem__(self, key, value):
logging.info('Setting to %r' % (key, value))
super().__setitem__(key, value)
该类与它的父类dict具有相同的功能,但是它扩展了__setitem__方法,使得当一个值更新时有一个log入口。通过建立一个log入口,该方法使用super()函数去委派实际的根据键值对去更新字典的工作。
class LoggingDict(SomeOtherMapping): # new base class
def __setitem__(self, key, value):
logging.info('Setting to %r' % (key, value))
super().__setitem__(key, value) # no change needed
除了隔绝改变,computed indirection另一个主要的优势是,有人可能不熟悉来自静态语言的人。因为间接性是在运行时计算的,我们有去影响计算的可能,使得间接性将指向其它的类。
class LoggingOD(LoggingDict, collections.OrderedDict):
pass
对我们的新类,祖先树为:LoggingOD, LoggingDict, OrderedDict, dict, object。针对我们的目的,重要的结果是OrderedDict位于LoggingDict之后,dict之前。这意味着super()调用在LoggingDict.__setitem__ 分派key/value更新到OrderedDict,而不是dict。
>>> print(LoggingOD.__mro__)
(,
,
,
,
)
如果我们的目的是用我们喜欢的MRO创建一个子类,我们需要知道它是如何被计算的。原则很简单。顺序包括:它本身,它的基类,它的基类的基类,等等,直到到了object对象,这是所有类的基类。该序列的排序使得一个类总是出现在它的父类之前,如果有多个父类的话,它们保持与类定义时父类相同的顺序。
class Shape:
def __init__(self, shapename, **kwds):
super.shapename = shapename
super().__init__(**kwds)
class ColoredShape(Shape):
def __init__(self, color, **kwds):
self.color = color
super().__init__(**kwds)
cs = ColoredShape(color='red', shapename='circle')
2)看一下使得调用者/被调用者参数匹配的策略,让我们现在看一下如何确保目标参数存在。
class Root:
def draw(self):
# the delegation chain stops here
assert not hasattr(super(), 'draw')
class Shape(Root):
def __init__(self, shapename, **kwds):
self.shapename = shapename
super().__init__(**kwds)
def draw(self):
print('Drawing. Setting shape to:', self.shapename)
super().draw()
class ColoredShape(Shape):
def __init__(self, color, **kwds):
self.color = color
super().__init__(**kwds)
def draw(self):
print('Drawing. Setting color to:', self.color)
super().draw()
cs = ColoredShape(color='blue', shapename='square')
cs.draw()
如果一个子类想要拒绝其他类进入MRO,这些其他类也需要继承自Root,这使得调用draw()没有路径可以接近object,没有被Root.draw所阻止。这应该清晰地写入文档,是的想要写新的合作类的人知道子类应该来自于Root。这个限制与Python自己的需求,所有新的异常必须继承自BaseException,没有多大的不同,
class Moveable:
def __init__(self, x, y):
self.x = x
self.y = y
def draw(self):
print('Drawing at position:', self.x, self.y)
如果我们想要使用这个类用我们的合作地设计ColoredShape层次,我们需要创建一个有一个必须super()调用的自适应器。
class MoveableAdapter(Root):
def __init__(self, x, y, **kwds):
self.movable = Moveable(x, y)
super().__init__(**kwds)
def draw(self):
self.movable.draw()
super().draw()
class MovableColoredShape(ColoredShape, MoveableAdapter):
pass
MovableColoredShape(color='red', shapename='triangle',
x=10, y=20).draw()
from collections import Counter, OrderedDict
class OrderedCounter(Counter, OrderedDict):
'Counter that remembers the order elements are first seen'
def __repr__(self):
return '%s(%r)' % (self.__class__.__name__,
OrderedDict(self))
def __reduce__(self):
return self.__class__, (OrderedDict(self),)
oc = OrderedCounter('abracadabra')
这篇文章翻译自Raymond Hettinger写的super()的权威文章。
此文对本文翻译亦有帮助。
此文写的也特别好。