0

编辑:我正在使用 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,我只是想在这里理解语言的语法和机制。谢谢大家!

4

2 回答 2

3
  1. 您应该使用新型类。如果这是 Python 3,那么您就是;如果您使用的是 Python 2,您应该继承自object(或其他一些新样式的类)。
  2. 调用祖先方法的常用方法是使用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

于 2012-09-05T02:26:01.017 回答
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()supersuper

于 2012-09-05T02:17:47.123 回答