【发布时间】:2021-04-20 17:13:46
【问题描述】:
子类的方法与基类的相应方法具有相同的签名是一种很好的做法。如果违反这一原则,PyCharm 会给出警告:
Signature of method does not match signature of base method in class
这个原则有(至少)一个例外:Python 初始化方法__init__。子类通常具有与其父类不同的初始化参数。它们可能有额外的参数,也可能有更少的参数,通常是通过对父类的参数使用一个常量值来获得。
由于 Python 不支持具有不同签名的多个初始化方法,因此具有不同构造函数的 Pythonic 方式称为工厂方法(例如:https://stackoverflow.com/a/682545/10816965)。
PyCharm 认为这些工厂方法也不例外,子类的方法应该与对应的父类具有相同的签名。当然,我可以忽略这些警告——因为这些工厂方法类似于__init__ 或__new__,我认为可以认为这些警告是错误的。
但是,我想知道我是否在这里遗漏了什么,并且我的编码风格不是最佳实践。
所以我的问题是:这是 PyCharm 的意外行为,还是这种模式确实有更 Pythonic 的方式?
class A:
@classmethod
def from_something(cls, something):
self = cls()
# f(self, something)
return self
def __init__(self):
pass
class B(A):
@classmethod
def from_something(cls, something, param): # PyCharm warning:
# Signature of method 'B.from_something()' does not match
# signature of base method in class 'A'
self = cls(param)
# g(self, something, param)
return self
def __init__(self, param):
super().__init__()
self.param = param
class C:
@classmethod
def from_something(cls, something, param):
self = cls(param)
# f(self, something, param)
return self
def __init__(self, param):
self.param = param
class D(C):
@classmethod
def from_something(cls, something): # PyCharm warning: Signature of
# method 'D.from_something()' does not match signature of base
# method in class 'C'
self = cls()
# g(self, something)
return self
def __init__(self):
super().__init__(None)
【问题讨论】:
-
我认为这是因为使用不同的签名你不能再替换,比如用
B实例替换A实例,用OOP 术语说B仍然是A。请注意,如果该方法是从基类使用的相同something类型创建子类的工厂,为什么它需要更多参数。如果B是A,则应该可以以相同的方式创建它。如果你不在乎,也许这不是问题。但是,您仍然可以使用*args, **kwargs参数来保持相同的明显签名。 -
是的,例如方法,这就是它们应该具有相同签名的原因。但是,对于诸如工厂方法之类的类方法,情况并非如此。使用
*args和**kwargs不是我的选择,我宁愿忽略警告。 -
你能详细说明为什么类方法不是这样吗?
-
另见答案here
-
@progmatico 我会说类方法通常不打算从实例中调用。尽管 Python 允许这样做,但我认为,如果您将
b或B的实例称为b.from_something(something)而不是B.from_something(something),那么这也是不好的编码风格。在某些情况下,从实例调用类方法可能是合适的,但至少对于工厂方法,我会避免这种情况。
标签: python inheritance pycharm subclassing factory-method