在typing.NamedTuple上获取字段默认值的优雅方法

but*_*tla 6 python

假设我的样子是typing.NamedTuple这样的:

class Bla(typing.NamedTuple):
    a: str
    b: int = 666
    c: str = 'blah'
Run Code Online (Sandbox Code Playgroud)

我知道我可以为Bla._field_types我提供字段名称到其类型的映射,并Bla._field_defaults为我提供字段名称到其默认值的映射。

我知道不应该使用任何前缀的规则_,但我知道命名元组并不总是这种情况。例如,_asdict()即使在旧namedtuple版本中collections,现在时也可以使用,它只是有下划线以避免潜在的名称冲突。

同时,还有,其工作原理与本例typing.get_type_hints类似:_field_types

>>> Bla._field_types
OrderedDict([('a', <class 'str'>), ('b', <class 'int'>), ('c', <class 'str'>)])
>>> typing.get_type_hints(Bla)
{'a': <class 'str'>, 'b': <class 'int'>, 'c': <class 'str'>}
Run Code Online (Sandbox Code Playgroud)

但这是一个更通用的函数,它比typing.NamedTuples 可以做更多的事情。

那么有人知道不使用的原因吗_field_defaults

为了提供一些上下文,我需要一段动态代码,该代码继承不同的类typing.NamedTuple并根据环境中的值实例化它们。

Mes*_*ion 2

_field_types仅在 中可用typing.NamedTuple,它从来不是底层collections.namedtupleAPI 的一部分。这是一个已弃用的功能,并在 Python 3.9 中被删除,因此不应在较新的代码中使用它。

_field_defaults另一方面,是NamedTuples 的记录功能,在两个模块中都可用。API 的一部分,而不是内部功能或实现细节,因此请随意使用它。

此外,并不是说“根本不应该使用前缀为 的东西”_。约定是它不应该在定义类的实例之外使用。因此,在任何类(或其子类)方法中使用它都是完全可以的。因此,如果您确实想遵循约定,您可以添加一个公开的“公共”方法_field_defaults

class Bla(typing.NamedTuple):
    a: str
    b: int = 666
    c: str = 'blah'

    def field_defaults(self):
        return self._field_defaults
Run Code Online (Sandbox Code Playgroud)

请注意,这只是一个约定,而不是硬性规则。NamedTuple在它甚至不适用的情况下:_field_defaults仅具有前导_,原因与您提到的相同_asdict():以防止与实际字段名称发生冲突。这里_的意思是“不引人注目”,而不是“私密”。