子类方法在python中覆盖

时间:2012-09-15 13:51:47

标签: python override subclass

我写了一个python的测试代码,如:

class Parent(object):
    @classmethod
    def dispatch(klass):
        print 'klass = %s' % klass
        return klass().__dispatch()
    def __dispatch(self):
        print 'This Parent.__dispatch()'
        print self


class Child(Parent):
    def __dispatch(self):
        print 'This Child.__dispatch()'
        print self


if __name__=='__main__':
    print 'Calling Parent.dispatch() ...\n'
    Parent.dispatch()
    print ''
    print 'Calling Child.dispatch() ...\n'
    Child.dispatch()
    print '\n-END'

输出是:

 Calling Parent.dispatch() ...

 klass = <class '__main__.Parent'> 
 This Parent.__dispatch()
 <__main__.Parent object at 0x0000000002D3A2E8>

 Calling Child.dispatch() ...

 klass = <class '__main__.Child'> 
 This Parent.__dispatch()
 <__main__.Child object at 0x0000000002D3A2E8>

 -END

为什么没有调用Child类的覆盖方法'__dispatch(self)',这很奇怪。

有人能解释一下吗?

谢谢。

2 个答案:

答案 0 :(得分:5)

以双下划线开头的方法名称会自动损坏;在内部,字符串_ClassName前置于方法名称:

>>> class Foo(object):
...     def __bar(self):
...         pass
... 
>>> Foo.__dict__.keys()
['__dict__', '__module__', '__weakref__', '__doc__', '_Foo__bar']

此类重命名也适用于在类中的任何其他方法中引用此方法名称的任何内容。

因此,您的__dispatch()方法已重命名为_Parent__dispatch()dispatch()方法已更改,而是调用self._Parent__dispatch()。同样,您的Child类有一个_Child__dispatch()方法,因此不会覆盖它的超类_Parent__dispatch()方法。

这就是你看到你看到的结果的原因;将您的__dispatch()方法重命名为_dispatch()(只有一个下划线),它将按预期工作。

为什么python这样做?它是一种提供私有属性和方法的形式,它们不会被从它们继承的类意外地覆盖。请参阅Python表达式参考中的private name mangling

PEP 8 Python Style Guide有关于私人名称修改的说法:

  

如果您的类要进行子类化,并且您具有属性   您不希望子类使用,请考虑使用它们命名   双引导下划线和没有尾随下划线。这会调用   Python的名称修改算法,其中类的名称是   被破坏成属性名称。这有助于避免属性名称   碰撞应该是子类无意中包含的属性   同名。

     

注1:请注意,在错位中只使用简单的类名   name,所以如果子类选择相同的类名和属性   名字,你仍然可以得到名字冲突。

     

注2:名称修改可以进行某些用途,例如调试和   __getattr__(),不太方便。但是名称为mangling算法   有详细记录,易于手动执行。

     

注3:不是每个人都喜欢名字错误。尝试平衡需要   避免意外姓名冲突,可能会被高级来电者使用。

答案 1 :(得分:0)

您是否尝试过调用方法_dispatch而不是__dispatch?

关键是__dispatch在内部被翻译成_NameOfTheClass_dispatch(或类似的东西,以提供某种'私有'成员函数行为)。这就是你的覆盖失败的原因。

如果使用_dispatch,则成员函数的名称不受下划线影响,程序的行为符合您的要求。