编辑:我正在使用Python 3(有些人问过)。
我认为这只是一个语法问题,但我想确定没有什么是我遗漏的。请注意Foo和Bar的实现方式的语法差异。他们实现了同样的目标,我想确保他们真的做同样的事情。输出表明只有两种方法可以做同样的事情。是这样的吗?
代码:
class X:
def some_method(self):
print("X.some_method called")
class Y:
def some_method(self):
print("Y.some_method called")
class Foo(X,Y):
def some_method(self):
X().some_method()
Y().some_method()
print("Foo.some_method called")
class Bar(X,Y):
def some_method(self):
X.some_method(self)
Y.some_method(self)
print("Bar.some_method called")
print("=== Fun with Foo ===")
foo_instance = Foo()
foo_instance.some_method()
print("=== Fun with Bar ===")
bar_instance = Bar()
bar_instance.some_method()
输出:
=== Fun with Foo ===
X.some_method called
Y.some_method called
Foo.some_method called
=== Fun with Bar ===
X.some_method called
Y.some_method called
Bar.some_method called
PS - 希望不言而喻,但这只是一个抽象的例子,让我们不要担心为什么我想在两个祖先上调用some_method,我我只是想在这里理解语言的语法和机制。谢谢大家!
答案 0 :(得分:3)
object
(或其他一些新式的类)。super
。在标准文档中阅读它,以及有关它如何运作的其他优秀文章。永远不建议以您的方式调用方法,因为(a)在进一步继承时它将是脆弱的; (b)通过硬编码对类的引用来增加维护工作量。 更新:以下是展示如何使用super
来实现此目的的示例:http://ideone.com/u3si2
另请参阅:http://rhettinger.wordpress.com/2011/05/26/super-considered-super/
更新2:这是python 2的一个小库,它为每个方法添加__class__
变量和无参数super
,以避免对当前名称进行硬编码:https://github.com/marcintustin/superfixer
答案 1 :(得分:2)
他们不一样。 X()
创建了一个类X
的对象。执行X().someMethod()
时,您创建一个新对象,然后在该对象上调用该方法,而不是self
。 X.someMethod(self)
是你想要的,因为它在同一个对象上调用了继承的方法。
如果您的方法实际对self
对象执行任何操作,您将看到区别。例如,如果您将self.blah = 8
放入方法中,那么在X.someMethod(self)
之后,您调用它的对象将设置blah
属性,但在X().someMethod()
后它不会。 (相反,您将创建一个新对象,在其上设置blah
,然后抛弃该新对象而不使用它,保持原始对象不变。)
以下是修改代码的简单示例:
>>> class X:
...
... def some_method(self):
... print("X.some_method called on", self)
...
... class Y:
...
... def some_method(self):
... print("Y.some_method called on", self)
...
... class Foo(X,Y):
...
... def some_method(self):
... X().some_method()
... Y().some_method()
... print("Foo.some_method called on", self)
...
... class Bar(X,Y):
...
... def some_method(self):
... X.some_method(self)
... Y.some_method(self)
... print("Bar.some_method called on", self)
>>> Foo().some_method()
('X.some_method called on', <__main__.X instance at 0x0142F3C8>)
('Y.some_method called on', <__main__.Y instance at 0x0142F3C8>)
('Foo.some_method called on', <__main__.Foo instance at 0x0142F3A0>)
>>> Bar().some_method()
('X.some_method called on', <__main__.Bar instance at 0x0142F3C8>)
('Y.some_method called on', <__main__.Bar instance at 0x0142F3C8>)
('Bar.some_method called on', <__main__.Bar instance at 0x0142F3C8>)
请注意,当我使用Foo
时,打印的对象不一样;一个是X实例,一个是Y实例,最后一个是我调用方法的原始Foo实例。使用Bar
时,它在每个方法调用中都是相同的对象。
(在某些情况下,您也可以使用super
来避免明确命名基类;例如,super(Foo, self).someMethod()
或Python 3只是super().someMethod()
。但是,如果您需要从两个基类直接调用继承的方法,super
可能不太适合。它通常针对每个方法只调用super
一次,将控制权传递给方法的下一个版本的情况。继承链,然后将它传递给下一个,等等。)