问题描述
TLDR;
我使用 @classmethod
作为我的类的构造函数,我需要为一个需要额外参数的特定子类使用不同的签名覆盖它。 PyCharm 给出关于覆盖具有不同签名的方法的警告。我想知道它是否也适用于 @classmethod
构造函数。
我正在将 IDE PyCharm 用于我的 Python 项目,并且我收到了以下关于重写类中方法的警告:
方法 [...] 的签名与类 [...] 中基方法的签名不匹配
我理解这与 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,data,specific):
super().__init__(common,data)
self.specific = specific
@classmethod
def from_directory(cls,specific):
all_data = [load_data(data_file) for data_file in get_data_files(data_dir)]
return [cls(common,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__
的参数。