如何在Python中重写父类的函数?
我在父类里有一个私有方法 def __pickSide(self):
,我想在子类中重写这个方法。但是,子类还是调用了从父类继承来的 def __pickSide(self):
。我该怎么重写这个函数呢?子类的方法名字和父类的方法名字完全一样。
3 个回答
4
使用
__foo
这样的命名方式会把方法的名字搞得复杂,这样在需要访问它的时候就会变得麻烦。我建议不要使用这种方式,这样测试的时候会顺利很多。在Python中没有“私有”这个概念,即使有,也不会阻止你这样做。(这就是一些有“私有”概念的编程语言的目的。)
通常的约定是,用一个 前导下划线 来表示某个属性不是类的公共接口的一部分,比如
_foo
。这样就足够让你的代码清晰,能够区分内部细节和公共接口。
5
你遇到的问题是,双下划线会让函数的名字变得复杂,即使在调用的时候也是如此。这会导致多态性无法正常工作,因为它变复杂后的名字是根据定义这个方法的类的名字来决定的,而不是根据你正在使用的对象的类的名字。把双下划线换成其他符号就能解决这个问题。
36
我们来看一个最简单的例子:
from dis import dis
class A(object):
def __pick(self):
print "1"
def doitinA(self):
self.__pick()
class B(A):
def __pick(self):
print "2"
def doitinB(self):
self.__pick()
b = B()
b.doitinA() # prints 1
b.doitinB() # prints 2
dis(A.doitinA)
print
dis(B.doitinB)
反汇编的结果如下:
8 0 LOAD_FAST 0 (self)
3 LOAD_ATTR 0 (_A__pick)
6 CALL_FUNCTION 0
9 POP_TOP
10 LOAD_CONST 0 (None)
13 RETURN_VALUE
15 0 LOAD_FAST 0 (self)
3 LOAD_ATTR 0 (_B__pick)
6 CALL_FUNCTION 0
9 POP_TOP
10 LOAD_CONST 0 (None)
13 RETURN_VALUE
你可以看到,Python 会把以两个下划线开头的函数名(还有对这些名字的访问)改成一个包含类名的名字——在这个例子中是 _A__pick
和 _B__pick
。这意味着,函数定义在哪个类里,就决定了调用哪个 __pick
方法。
解决这个问题的方法很简单,就是避免使用伪私有的方法,直接去掉两个下划线。比如,可以用 _pick
代替 __pick
。