Python方法重写,签名重要吗?
假设我有
class Super():
def method1():
pass
class Sub(Super):
def method1(param1, param2, param3):
stuff
这样写对吗?调用method1的方法总是会去子类吗?我的计划是有两个子类,每个子类都用不同的参数来重写method1。
6 个回答
4
如果可以使用默认参数的话,你可以这样做:
>>> class Super():
... def method1(self):
... print("Super")
...
>>> class Sub(Super):
... def method1(self, param1="X"):
... super(Sub, self).method1()
... print("Sub" + param1)
...
>>> sup = Super()
>>> sub = Sub()
>>> sup.method1()
Super
>>> sub.method1()
Super
SubX
52
Python是允许这样做的,但如果method1()
是打算从外部代码中调用的话,你可能需要重新考虑一下,因为这样做违反了里氏替换原则,所以可能不会总是正常工作。
154
在Python中,方法其实就是和类关联的字典里的键值对。当你从一个基类派生出一个新类时,你实际上是在说,方法名会先在新类的字典里查找,如果找不到再去基类的字典里查找。如果你想“重写”一个方法,只需要在新类里重新声明这个方法就可以了。
那么,如果你在新类里改变了重写方法的签名(也就是方法的参数),会发生什么呢?如果你在新类的实例上调用这个方法,一切都正常,但如果你在基类的实例上调用,就会出错,因为基类对同一个方法名使用了不同的签名。
不过,常常会有这样的情况,你希望新类的方法有额外的参数,并且希望在基类上调用时也不会出错。这就是所谓的“里氏替换原则”(Liskov substitution principle,简称LSP),它保证了如果一个人从基类切换到新类,或者反过来,他们的代码不需要大改动。要在Python中做到这一点,你需要用以下方法设计你的基类:
class Base:
# simply allow additional args in base class
def hello(self, name, *args, **kwargs):
print("Hello", name)
class Derived(Base):
# derived class also has unused optional args so people can
# derive new class from this class as well while maintaining LSP
def hello(self, name, age=None, *args, **kwargs):
super(Derived, self).hello(name, age, *args, **kwargs)
print('Your age is ', age)
b = Base()
d = Derived()
b.hello('Alice') # works on base, without additional params
b.hello('Bob', age=24) # works on base, with additional params
d.hello('Rick') # works on derived, without additional params
d.hello('John', age=30) # works on derived, with additional params
上面的代码会打印出:
Hello Alice Hello Bob Hello Rick Your age is None Hello John Your age is 30。