具有不同签名的 Python 类方法构造函数继承



TLDR;我正在使用@classmethod作为我的类的构造函数,我需要为一个需要额外参数的特定子类使用不同的签名覆盖它。PyCharm 发出有关使用不同签名覆盖方法的警告。我想知道它是否也适用于@classmethod构造函数。


我正在为我的 python 项目使用 IDE PyCharm,并且收到以下有关覆盖类中方法的警告:

方法的签名 [...] 与类中基本方法的签名不匹配 [...]

我知道这与 Liskov 替换原则有关,这意味着父类的对象应始终可由子类的对象替换。

但是,就我而言,我正在覆盖用作构造函数的@classmethod,遵循某种工厂模式。我的代码的简化如下:

class Parent:
def __init__(self, common, data):
self.common = common
self.data = data
@classmethod
def from_directory(cls, data_dir, common):
all_data = [load_data(data_file) for data_file in get_data_files(data_dir)]
return [cls(common, data) for data in all_data]
class ChildA(Parent):
def __init__(self, common, data, specific):
super().__init__(common, data)
self.specific = specific
@classmethod
def from_directory(cls, data_dir, common, specific):
all_data = [load_data(data_file) for data_file in get_data_files(data_dir)]
return [cls(common, data, specific) for data in all_data]

在这个例子中,基本上我有一个父类Parent,它有一些所有子类都将继承的公共属性,以及一些特定的子类ChildA,它有一个额外的、特定于子类的属性。

由于我使用@classmethod作为构造函数,因此我假设 Liskov 原则不适用,就像可以用不同的签名覆盖__init__()方法一样。但是,PyCharm警告让我考虑是否有我可能错过的东西。我不确定我是否以敏感的方式使用@classmethod

我的主要问题是:PyCharm 在这里的警告是否过于热心,或者有什么理由应该避免上述模式?

此外,非常欢迎对我可能有的任何其他设计问题/误解提供任何反馈。

我会改进你的类方法。这里实际上提供了两个类方法:一个从数据文件创建类的实例,另一个从目录中的文件生成实例列表(使用第一个类方法)。此外,类方法不应该关心cls需要哪些参数:它只是传递它收到的任何内容(除了data,它知道并将提供或覆盖它从文件中读取的任何内容)。

class Parent:
def __init__(self, common, data, **kwargs):
super().__init__(**kwargs)
self.common = common
self.data = data
@classmethod
def from_file(cls, filename, **kwargs):
# If the caller provided a data argument,
# ignore it and use the data from the file instead.
kwargs['data'] = load_data(filename)
return cls(**kwargs)
@classmethod
def from_directory(cls, data_dir, **kwargs):
return [cls.from_file(data_file, **kwargs)
for data_file in get_data_files(data_dir)]

class ChildA(Parent):
def __init__(self, specific, **kwargs):
super().__init__(**kwargs)
self.specific = specific

请注意,您不再需要覆盖Parent.from_directory;对于它收到的用于__init__的参数,它已经是不可知的。

最新更新