您可能知道,这是在python中定义命名元组的最新类型:
from typing import NamedTuple
class MyType(NamedTuple):
id: int = 0
name: str = 0
Run Code Online (Sandbox Code Playgroud)
定义类型后,Python解释器定义一个获取ID和名称的默认构造函数,您可以使用字段实例化新对象。现在,我想使用一个字符串初始化一个新对象,并在函数中对其进行解析。如何定义另一个构造函数而不破坏良好的默认构造函数?
如何定义另一个构造函数而不破坏良好的默认构造函数?
你不能 Python类不能有多个__new__方法(或者,如果您要表示“初始化器”,则__init__方法)只能是一个。
但是有一种简单的方法可以解决此问题:备用构造函数惯用语:您编写了@classmethod一种提供构造实例的替代方法的。标准库中有很多示例,例如datetime.now和datetime.utcfromtimestamp。基本内建类型中甚至还有一些示例,例如int.from_bytes。
运作方式如下:
class MyType(NamedTuple):
id: int = 0
name: str = 0
@classmethod
def from_string(cls, string_to_parse):
id, name = … your parsing code here …
return cls(id, name)
Run Code Online (Sandbox Code Playgroud)
当然,这与collections.namedtuple子类@dataclass,或普通类有太多不同的构造方法一样。
如果确实要这样做,另一种方法是为丑陋的构造函数提供仅关键字的参数,或者根据传递的内容而具有不同含义的参数。使用NamedTuple,您将不得不以这种方式插入一个额外的类,或者在创建后对该类进行monkeypatch,因为否则,没有记录的方法可以获取默认的构造函数实现。
所以:
class _MyType(NamedTuple):
id: int = 0
name: str = 0
class MyType(_MyType):
def __new__(cls, id: int=None, name: str=None, *, parseything: str=None):
if parseything:
if id is not None or str is not None:
raise TypeError("don't provide both")
id, name = … your parsing code here …
return super().__new__(cls, id, name)
Run Code Online (Sandbox Code Playgroud)
……或者,如果您更喜欢猴子补丁:
class MyType(NamedTuple):
id: int = 0
name: str = 0
_new = MyType.__new__
def __new__(cls, id=None, name=None, *, parseything=None):
if parseything:
if id is not None or str is not None:
raise TypeError("don't provide both")
id, name = … your parsing code here …
return _new(cls, id, name)
MyType.__new__ = __new__
del _new
del __new__
Run Code Online (Sandbox Code Playgroud)
…,或者,如果您想更多地使用range-style丑陋的API,可以使用以下两种方法之一:
def __new__(cls, id_or_parsey_thing: Union[int,str]=None,
name: str=None):
if isinstance(id_or_parsey_thing, str):
if name is not None:
raise TypeError("don't provide both")
id, name = … your parsing code here …
else:
id = id_or_parsey_thing
# super().__new__ or _new here
Run Code Online (Sandbox Code Playgroud)