[英]Python classmethod constructor inheritance with different signature
TLDR; TLDR; I am using a @classmethod
as a constructor for my class, and I need to override it with a different signature for one specific child class that needs extra parameters.我正在使用@classmethod
作为我的 class 的构造函数,并且我需要为需要额外参数的特定子 class 使用不同的签名覆盖它。 PyCharm gives a warning about overriding a method with different signature. PyCharm 给出了关于覆盖具有不同签名的方法的警告。 I wonder whether it also applies to @classmethod
constructors.我想知道它是否也适用于@classmethod
构造函数。
I am using the IDE PyCharm for my python project and I have received the following warning regarding the overriding of a method in a class:我正在为我的 python 项目使用 IDE PyCharm 并且我收到以下关于覆盖 ZABB14DC2A2 中的方法的警告:
Signature of method [...] does not match signature of base method in class [...]方法的签名 [...] 与 class [...] 中的基本方法的签名不匹配
I understand this is related to the Liskov substitution principle, meaning objects of a parent class should always be replaceable by objects of a child class.我知道这与 Liskov 替换原则有关,这意味着父 class 的对象应该始终可以被子 class 的对象替换。
However, in my case I am overriding a @classmethod
which is used as a constructor, following some sort of factory pattern.但是,在我的情况下,我正在重写用作构造函数的@classmethod
,遵循某种工厂模式。 A simplification of my code would be as follows:我的代码的简化如下:
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]
In this example, basically I have a parent class Parent
with some common attribute that all child classes will inherit, and some particular child class ChildA
which has an extra, subclass-specific attribute.在这个例子中,基本上我有一个父 class Parent
,它有一些所有子类都将继承的公共属性,还有一些特定的子 class ChildA
,它有一个额外的子类特定属性。
Since I am using the @classmethod
as a constructor, I assume the Liskov principle does not apply, just in the same way that the __init__()
method can be overridden with a different signature.由于我使用@classmethod
作为构造函数,我假设 Liskov 原则不适用,就像可以用不同的签名覆盖__init__()
方法一样。 However, the PyCharm warning has made me consider whether there is something I might have missed.然而,PyCharm 警告让我考虑是否有我可能遗漏的东西。 I am not sure whether I am using the @classmethod
in a sensitive way.我不确定我是否以敏感的方式使用@classmethod
。
My main question is then: Is PyCharm being overzealous with its warnings here or is there any reason the pattern described above should be avoided?那么我的主要问题是: PyCharm 是否过于热衷于此处的警告,或者是否有任何理由应该避免上述模式?
Also, any feedback about any other design issues / misconceptions I might have is most welcome.此外,任何关于我可能有的任何其他设计问题/误解的反馈都是非常受欢迎的。
I would refine your class method.我会改进你的 class 方法。 There are really two class methods to provide here: one that creates an instance of the class from a data file, and one that produces a list of instances from the files in a directory (using the first class method).这里实际上提供了两种class 方法:一种从数据文件创建 class 的实例,另一种从目录中的文件生成实例列表(使用第一个 class 方法)。 Further, the class methods shouldn't care about which arguments cls
will need: it just passes on whatever it receives (with the exception of data
, which it knows about and will provide or override with whatever it reads from a file).此外, class 方法不应该关心哪个 arguments 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
Notice that you no longer need to override Parent.from_directory
;请注意,您不再需要覆盖Parent.from_directory
; it's already agnostic about what arguments it receives that are intended for __init__
.它已经不知道它收到的 arguments 是用于__init__
的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.