在 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