Python中如何覆盖方法的默认参数?

6

方法默认参数可以被覆盖,看起来是这样的:

>>> class B:
...     def meth(self, r=True): print r
>>> class D(B):
...     def meth(self, r=False): print r
... D().meth()
False
>>> B().meth()
True

这怎么可能?这被认为是不好的风格吗?

附录(2014.11.23):用例是在遗留代码中添加默认参数以修改方法行为 - 不应由调用者设置 - 应将其命名为“_r”。 - Mr_and_Mrs_D
3个回答

14

您可以随意更改重写方法的签名。Python不会介意:

class Base:
    def foo(self, x, y):
        pass

class Deriv(Base):
    def foo(self, blah=100):
        pass

但如果你问

这是否被认为是不好的风格?

答案是肯定的,因为它违反了重要的Liskov替换原则

如果Deriv扩展自Base,则必须能够替换所有Base的出现而不破坏程序。

换言之,派生类必须实现基类提供的所有契约。特别是,重写的方法必须具有相同的签名和类似的语义。由于Python在这方面没有帮助,您必须手动控制,并借助您的IDE(这里是Intellij IDEA):

enter image description here

回答您关于覆盖默认参数的具体问题,我想答案是“这取决于”。如果该参数是仅在内部使用且不影响对象的可观察行为的选项,则更改它是完全可以接受的:

class Buffer:
    def __init__(self, init_size=16):

class BigBuffer(Buffer):
    def __init__(self, init_size=1024):

另一方面,如果参数对语义有实质性影响,则应将其视为合同的一部分,不应被覆盖。例如,以下代码会令人困惑:

class Test:
    def test_equal(self, a, b, fail_if_equal=False):

class MyTest(Test):
    def test_equal(self, a, b, fail_if_equal=True):

Pycharm?是的,我使用它。关于更改签名的风格不好的问题(正如您的图像中显示的那样,Pycharm甚至有一个警告),但在这种特定情况下,我更改了默认值-没有警告。我认为这是合法的,因为Derived.meth()应该表现出不同的行为-我只是通过更改默认值来实现这一点... - Mr_and_Mrs_D
@Mr_and_Mrs_D:更新了答案以回答您的具体问题。 - georg
1
谢谢 - 图中是Intellij IDEA还是Pycharm? - Mr_and_Mrs_D
@Mr_and_Mrs_D:它是 IDEA,版本 12(不是最新的)。 - georg

0

这是绝对允许的,但可能会让您的调用者感到非常困惑。他们不应该能够像使用 B 对象一样使用 D 对象吗?


是的,永远不要传递参数 ;) - 这个机制是什么? - Mr_and_Mrs_D

0
这怎么可能?机制是什么?
你只需在派生类中覆盖整个方法即可。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接