Python中有一个习惯用法,即使用类方法来提供构造对象的附加方法,其中转换/转换逻辑保留在类方法中,而
__init__()
仅用于初始化字段。例如:
class Foo:
field1: bytes
def __init__(self, field1: bytes):
self.field1 = field1
@classmethod
def from_hex(cls, hex: str) -> Foo:
'''
construct a Foo from a hex string like "12:34:56:78"
'''
return cls(field1=bytes.fromhex(hex.replace(':', ' ')))
现在,假设我定义了一个从 Foo 派生的类:
class Bar(Foo):
field2: str
def __init__(self, field1: bytes, field2: str):
Foo.__init__(self, field1)
self.field2 = field2
考虑到这个层次结构,我想定义一个构造函数
Bar.from_hex_with_tag()
,它将作为Foo.from_hex()
的扩展:
class Bar(Foo):
<...>
@classmethod
def from_hex_with_tag(cls, hex: str, tag: str) -> Bar:
return cls(
field1=bytes.fromhex(hex.replace(':', ' ')), # duplicated code with Foo.from_hex()
field2=tag
)
如何在
Foo.from_hex()
中重复使用 Bar.from_hex_with_tag()
?
重用
classmethod
依赖于一切遵守里氏替换原则。您的子类不遵守它(它的初始化程序需要额外的参数),因此您能做的最好的事情就是提取父类中的类型转换代码(可能作为下划线前缀的 @staticmethod
实用程序),以便父类孩子也可以使用。
例如,您可能会这样做:
class Foo:
field1: bytes
def __init__(self, field1: bytes):
self.field1 = field1
@staticmethod
def _field_from_hex(hex: str) -> bytes:
return bytes.fromhex(hex.replace(':', ' '))
@classmethod
def from_hex(cls, hex: str) -> Foo:
'''
construct a Foo from a hex string like "12:34:56:78"
'''
return cls(field1=self._field_from_hex(hex))
所以
Bar
可以是:
class Bar(Foo):
<...>
@classmethod
def from_hex_with_tag(cls, hex: str, tag: str) -> Bar:
return cls(
field1=self._field_from_hex(hex),
field2=tag
)