geekdoc-python-zh/docs/pythonlibrary/python-201-what-is-super.md

79 lines
5.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Python 201:什么是超级?
> 原文:<https://www.blog.pythonlibrary.org/2014/01/21/python-201-what-is-super/>
Python 编程语言在 2.2 版本中添加了 **super()** 类型。出于某种原因,这仍然是一个很多初学者不理解的话题。我的一个读者最近问我关于它的问题,由于我并不真正使用它,我决定做一些研究,希望自己能理解它的用法,这样我就能解释什么是 super 以及为什么你会使用它。我们将花一些时间来看看不同的人对超级的定义,然后看一些例子来试图弄清楚这一点。
### 什么是超级?
下面是官方的 [Python 文档](http://docs.python.org/2/library/functions.html#super)对**超级** : *返回一个代理对象,该对象将方法调用委托给父类或兄弟类。这对于访问在类中被重写的继承方法很有用。搜索顺序与 getattr()使用的顺序相同,只是跳过了类型本身。*
几年前Cody Precord 发布了一本 wxPython 食谱,其中他一直使用 super。这在 wxPython 邮件列表上引起了几个星期对 super 的讨论。让我们来看看其中的一些[线程](https://groups.google.com/forum/?hl=en&fromgroups=#!topic/wxpython-users/-YYLRZ9NvFs)。
wxPython 的创建者 Robin Dunn 陈述如下:*在大多数情况下没有任何区别。在有多重继承的情况下super()有助于确保在继承树上移动时遵循正确的
方法解析顺序(MRO)。*然后他链接到[斯塔克韦尔弗洛](http://stackoverflow.com/questions/576169/understanding-python-super)。
在另一个[主题](http://wxpython-users.1045709.n5.nabble.com/Super-object-usage-explanation-td3408498.html)中Tim Roberts(一个非常有经验的 Python 程序员)说:
这是一条“捷径”,允许你访问一个派生类的基类,而不必知道或键入基类名。比如:
```py
class This_is_a_very_long_class_name(object):
def __init__(self):
pass
class Derived(This_is_a_very_long_class_name):
def __init__(self):
super(Derived,self).__init__() #1
This_is_a_very_long_class_name.__init__(self) #2
```
最后两行是同一事物的两种拼法。除了拼写之外这还允许您更改基类而不必遍历所有代码并替换基类名称。C++程序员经常在他们的派生类中使用 typedef 来实现这一点。
所以我从这两个陈述中得到的是,当你做多重继承时, **super** 是很重要的,但是除此之外,你是否使用它并不重要。如果你向下滚动第二个线程,你会看到 Robin Dunn 和 Tim Roberts 的几个例子,它们有助于说明使用 **super** 是有帮助的。让我们看看邓恩先生的例子。
*注意:下面的代码使用 Python 2.x 语法进行 super。在 Python 3 中,不需要传递类名,甚至不需要传递 self*
```py
class A(object):
def foo(self):
print 'A'
class B(A):
def foo(self):
print 'B'
super(B, self).foo()
class C(A):
def foo(self):
print 'C'
super(C, self).foo()
class D(B,C):
def foo(self):
print 'D'
super(D, self).foo()
d = D()
d.foo()
```
如果您运行这段代码您将得到字母“DBCA”(每行一个字母)作为输出。正如 Robin Dunn 在帖子中指出的“A”只被打印一次即使从它派生出两个类。这是因为 Python 的新样式类中固有的方法解析顺序(MRO)。你可以通过在类 D 的 foo 函数中的超级调用下面添加 **print D.__mro__** 来签出 MRO(注意:这只在基类是从**对象**派生的情况下才有效)。这个[栈溢出条目](http://stackoverflow.com/a/1848647/393194)对此进行了更详细的解释。如果你想好好读一读关于 MRO 的主题,我会推荐 Python.org 上的以下摘要:[http://www.python.org/download/releases/2.3/mro/](http://www.python.org/download/releases/2.3/mro/)。
现在你可能认为这个例子不仅抽象,而且没什么用,你可能是对的。这就是为什么值得在网上做一些额外的挖掘来寻找其他的例子。幸运的是,我记得几年前在 super 上看过 Raymond Hettinger 的一篇文章。他是 Python 的核心开发人员,经常在 PyCon 上发言。总之,他的文章给出了几个使用 super 向子类添加新特性的真实例子。我强烈推荐看看他的文章,因为它对以一种适用的方式解释**超级**大有帮助。甚至 super()的 Python 文档也链接到了他的文章!
这里有一个关于这个话题的很好的列表:
* 关于 super 的官方 Python [文档](http://docs.python.org/2/library/functions.html#super)
* 雷蒙德·赫廷格[对超级](http://rhettinger.wordpress.com/2011/05/26/super-considered-super/)的沉思
* [Python 的 Super 很俏皮,但是不能用](http://docs.python.org/2/library/functions.html)
* StackOverflow: [了解 Python 超级](http://stackoverflow.com/questions/576169/understanding-python-super)
* StackOverflow: [如何在 Python 中使用 super](http://stackoverflow.com/questions/222877/how-to-use-super-in-python)
* [了解 Python 的超级](http://blog.timvalenta.com/2009/02/understanding-pythons-super/)
* [如何有效使用 super()](http://code.activestate.com/recipes/577721-how-to-use-super-effectively-python-27-version/)-Python 2.7 版本(Python 菜谱)
* Zed Shaw 在他的在线书籍中对 super()的评论
* 方法解析顺序(MRO) [摘要](http://www.python.org/download/releases/2.3/mro/)