Python 方法重写,签名重要吗?
可以说我有
class Super():
def method1():
pass
class Sub(Super):
def method1(param1, param2, param3):
stuff
这是正确的吗?对method1的调用总是会转到子类吗?我的计划是有 2 个子类,每个子类都使用不同的参数覆盖 method1
Lets say I have
class Super():
def method1():
pass
class Sub(Super):
def method1(param1, param2, param3):
stuff
Is this correct? Will calls to method1 always go to the sub class? My plan is to have 2 sub classes each override method1 with different params
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
在Python中,方法只是附加到类的字典中的键值对。当您从基类派生类时,实质上是说方法名称将首先查看派生类字典,然后查看基类字典。为了“重写”一个方法,您只需在派生类中重新声明该方法即可。
那么,如果更改派生类中重写方法的签名会怎样?如果调用是在派生实例上,则一切正常,但如果在基实例上进行调用,则会收到错误,因为基类对同一方法名称使用不同的签名。
然而,在常见的情况下,您希望派生类方法具有附加参数,并且您希望方法调用在基类上也不会出现错误。这称为“里氏替换原则”(或LSP),它保证如果人从基地切换到派生实例或反之亦然,他们不必修改代码。要在 Python 中执行此操作,您需要使用以下技术设计基类:
上面将打印:
.
Play with this code
In Python, methods are just key-value pairs in the dictionary attached to the class. When you are deriving a class from a base class, you are essentially saying that method name will be looked into first derived class dictionary and then in the base class dictionary. In order to "override" a method, you simply re-declare the method in the derived class.
So, what if you change the signature of the overridden method in the derived class? Everything works correctly if the call is on the derived instance but if you make the call on the base instance, you will get an error because the base class uses a different signature for that same method name.
There are however frequent scenarios where you want derived class method have additional parameters and you want method call work without error on base as well. This is called "Liskov substitution principle" (or LSP) which guarantees that if person switches from base to derived instance or vice versa, they don't have to revamp their code. To do this in Python, you need to design your base class with the following technique:
Above will print:
.
Play with this code
Python 将允许这样做,但如果
method1()
旨在从外部代码执行,那么您可能需要重新考虑这一点,因为它违反了 LSP 因此并不总是能正常工作。Python will allow this, but if
method1()
is intended to be executed from external code then you may want to reconsider this, as it violates LSP and so won't always work properly.如果可以使用默认参数,你可以这样做:
You could do something like this if it's ok to use default arguments:
在Python中,所有类方法都是“虚拟的”(就C++而言)。因此,就您的代码而言,如果您想在超类中调用
method1()
,它必须是:并且方法签名确实很重要。你不能调用这样的方法:
In python, all class methods are "virtual" (in terms of C++). So, in the case of your code, if you'd like to call
method1()
in super class, it has to be:And the method signature does matter. You can't call a method like this:
它会起作用:
但是,通常不建议这样做。看看 S.Lott 的回答:具有相同名称和不同参数的方法有代码味道。
It will work:
However, this isn't generally recommended. Take a look at S.Lott's answer: Methods with the same name and different arguments are a code smell.
不,它不会,但当重写的方法与基本方法不匹配时,PyCharm 会生成警告。
方法“Baz.method1()”的签名与类“Foo”中基方法的签名不匹配
您可以通过添加
typing.Optional
作为键入提示。如果所有参数均为 None,您还可以使用 locals() 调用基本方法。Output:
No it doesn't but PyCharm will generate a warning when the overridden method doesn't match the base method.
Signature of method 'Baz.method1()' does not match signature of the base method in class 'Foo'
You can get around this warning by adding
typing.Optional
as a type hint. You can also use locals() to call the base method if all the parameters are None.Output: