在 namedtuple 中输入提示

Posted

技术标签:

【中文标题】在 namedtuple 中输入提示【英文标题】:Type hints in namedtuple 【发布时间】:2016-03-20 02:17:25 【问题描述】:

考虑以下代码:

from collections import namedtuple
point = namedtuple("Point", ("x:int", "y:int"))

上面的代码只是展示我想要实现的目标的一种方式。 我想用类型提示制作namedtuple

你知道任何优雅的方式来达到预期的结果吗?

【问题讨论】:

另外,从 py3.7 开始,您有 dataclass 选项:docs.python.org/3/library/dataclasses.html 【参考方案1】:

自 3.6 以来类型化命名元组的首选语法是

from typing import NamedTuple

class Point(NamedTuple):
    x: int
    y: int = 1  # Set default value

Point(3)  # -> Point(x=3, y=1)

编辑 从 Python 3.7 开始,考虑使用 dataclasses(您的 IDE 可能还不支持它们进行静态类型检查):

from dataclasses import dataclass

@dataclass
class Point:
    x: int
    y: int = 1  # Set default value

Point(3)  # -> Point(x=3, y=1)

【讨论】:

@JohnE; OP 专门要求命名元组。是的,数据类将更好地服务于命名元组的许多用例。但是引用优秀的Why not namedtuples:如果你想要一个有名字的元组,无论如何:去一个命名的元组 使用数据类,不可能像元组那样解构生成的对象 元组是不可变的。数据类不是(默认情况下)它确实具有接近元组行为的冻结标志。只是需要注意的事情。 如果数据类适合您,您可以更进一步,使用pydantic 包以优雅的方式在运行时强制执行类型检查。 数据类是不可订阅的,并且在迭代命名元组时它们也不是不可打包的,所以我认为它们远非完美的选择。【参考方案2】:

您可以使用typing.NamedTuple

来自文档

键入的版本namedtuple

>>> import typing
>>> Point = typing.NamedTuple("Point", [('x', int), ('y', int)])

这仅在 Python 3.5 及更高版本中存在

【讨论】:

我这样声明:GeoPoint = NamedTuple('GeoPoint', [('longitude', float), ('latitude', float)]) 然后我尝试 geo = GeoPoint(**data) 其中数据是包含所需键和值的字典,为 decimal.Decimal,并且不会发生浮点转换;(也没有打字错误:( :( 那么typing.NamedTuple 是如何工作的?见gist.github.com/andilabs/15002176b2bda786b9037077fa06cc71 @andi 键入不强制或强制转换变量,afaik。 在较新的版本中,您可以将 NamedTuples 声明为 Point = typing.NamedTuple("Point", x=int, y=int),这样更简洁、更短。【参考方案3】:

公平地说,NamedTuple 来自typing

>>> from typing import NamedTuple
>>> class Point(NamedTuple):
...     x: int
...     y: int = 1  # Set default value
...
>>> Point(3)
Point(x=3, y=1)

等于经典namedtuple:

>>> from collections import namedtuple
>>> p = namedtuple('Point', 'x,y', defaults=(1, ))
>>> p.__annotations__ = 'x': int, 'y': int
>>> p(3)
Point(x=3, y=1)

所以,NamedTuple 只是 namedtuple 的语法糖

下面,你可以从python 3.10的源代码中找到一个创建NamedTuple的函数。如我们所见,它使用collections.namedtuple 构造函数并从提取的类型中添加__annotations__

def _make_nmtuple(name, types, module, defaults = ()):
    fields = [n for n, t in types]
    types = n: _type_check(t, f"field n annotation must be a type")
             for n, t in types
    nm_tpl = collections.namedtuple(name, fields,
                                    defaults=defaults, module=module)
    nm_tpl.__annotations__ = nm_tpl.__new__.__annotations__ = types
    return nm_tpl

【讨论】:

语法糖是 解析器 可以用更基本的语法代替的东西。 NamedTuple 比这复杂一点,它是一个在运行时实际执行某些操作的函数。 是的,我知道它在运行时做了什么。它正在提取类型并将它们添加到使用构造函数collections.namedtuple 刚刚创建的namedtuple__annotations__ attr。为了更好地理解,我将该代码添加到答案中。

以上是关于在 namedtuple 中输入提示的主要内容,如果未能解决你的问题,请参考以下文章

Python 3.5 类型化的 NamedTuple 语法产生 SyntaxError

NamedTuple 声明并在一行中使用

python中namedtuple介绍

namedtuple._replace() 不像文档中描述的那样工作

namedtuple工厂函数精讲

namedtuple 的等式重载