从typing模块中使用List/Tuple等类型与直接引用list/tuple等类型有何区别?

263

使用 ListTuple 等与使用 typing 模块有何不同:

from typing import Tuple

def f(points: Tuple):
    return map(do_stuff, points)
与直接引用Python类型不同:
def f(points: tuple):
    return map(do_stuff, points)

何时应该使用其中一个而不是另一个?


3
看一下这个,我发现自己也曾经问过你同样的问题,直到我读了这个链接:https://docs.python.org/3/library/typing.html - MooingRawr
1
元组,通过列出元素类型来使用。例如:Tuple[int, int, str]。(来源:https://www.python.org/dev/peps/pep-0484/#the-typing-module) - Mazdak
可能是重复问题 https://dev59.com/KVoU5IYBdhLWcg3wzZLw - Mazdak
3个回答

298

直到Python 3.9 增加了对标准集合进行类型提示的支持,如果你想记录容器的内容所需的类型,你必须使用typing.Tupletyping.List

def f(points: Tuple[float, float]):
    return map(do_stuff, points)

在Python 3.8之前,tuplelist不支持作为通用类型使用。上面的示例说明了函数f需要points参数是一个包含两个float值的元组。

typing.Tuple在这里是特殊的,因为它允许您指定期望的元素数量和每个位置的类型。如果长度未设置并且要重复类型,请使用省略号:Tuple[float, ...]描述具有float的可变长度tuple

对于typing.List和其他序列类型,通常仅为所有元素指定类型;List[str]是一个任意大小的字符串列表。请注意,函数应优先采用typing.Sequence作为参数,而typing.List通常仅用于返回类型;一般来说,大多数函数将接受任何序列并仅进行迭代,但是当您返回一个list时,您确实返回了一个特定的可变序列类型。

如果仍需要支持Python 3.8或更早版本的代码,则即使当前未限制内容,也应始终选择typing通用类型。使用通用类型稍后添加约束更容易,因为生成的更改将更小。

如果您正在实现自定义容器类型并希望该类型支持泛型,则可以实现__class_getitem__钩子或从typing.Generic继承(它又实现了__class_getitem__)。


4
两者都将利用PEP 3107,但[]在PEP 484扩展PEP中未被描述。不遵循标准,您将无法获得仅遵循标准的工具的好处。例如,mypy可能无法正常工作。 - Peilonrayz
1
请注意,函数应首选将 typing.Sequence 作为参数,并且 typing.List 通常仅用于返回类型;一般来说,大多数函数会取任何序列并进行迭代,但当您返回列表时,您确实正在返回特定的可变序列类型。为什么函数不应该返回序列? - kolistivra
5
@kolistivra: 因为这会限制调用者对返回列表对象的操作。任何需要可变序列的操作都无法接受返回值。或者如果某个特定操作需要使用列表,也无法使用返回值。尽可能具体地设置返回值类型。 - Martijn Pieters
2
不要忘记 from typing import Tuple - Sparkofska
你的最后一段似乎不正确。“为了实现可以在运行时进行参数化并被静态类型检查器理解的自定义泛型类,用户应该继承已经实现了__class_getitem__()的标准库类,或者继承typing.Generic,它有自己的__class_getitem__()实现。” __class_getitem__主要是为了解决元类的限制而实现的一个细节。 - Peilonrayz
显示剩余4条评论

155

从Python 3.9(PEP 585)开始,tuplelist和其他各种类现在是泛型类型。现在更建议使用它们而不是它们的typing对应项。从Python 3.9开始,您现在可以这样做:

def f(points: tuple[float, float]):
    return map(do_stuff, points)

如果您不需要评估类型提示,则可以使用此语法在Python 3.7+中,因为PEP 563
from __future__ import annotations


def f(points: tuple[float, float]):
    return map(do_stuff, points)

每当可能时,应该选择非typing泛型,因为旧的typing.Tupletyping.List其他泛型已被弃用,并将在Python的后续版本中删除。
typing导入这些内容是不推荐的。由于PEP 563和最小化typing运行时影响的意图,此弃用不会生成DeprecationWarnings。相反,类型检查器可能会在检查的程序目标版本为Python 3.9或更高版本时警告有关此类弃用的使用。建议在项目范围内允许消除这些警告。
弃用的功能将在Python 3.9.0发布5年后的第一个Python版本中从typing模块中删除。

6
现在更倾向于使用这些内容,而不是它们的打字对应物。对于公共 Python 库来说,在 Python 3.9.0 发布后的4年内继续使用 typing 泛型是否有意义? - Mateen Ulhaq
1
不是反对@MateenUlhaq,但你能分享一下为什么这有道理吗? - MinneapolisCoder9
2
@MonkeySeeMonkeyDo 所以这些库适用于Python 3.0+。虽然你可以手动执行__future__.annotations所做的操作(def f(points: "tuple[float, float]")),但如果你需要在运行时评估类型提示,那么代码将无法正常工作。 - Peilonrayz
请注意,您必须使用方括号 - [] - 进行输入。如果尝试使用 tuple(float, float),将会出现 TypeError: tuple expected at most 1 argument, got 2 - codeananda
请注意,您在输入时必须使用方括号 - []。如果您尝试使用 tuple(float, float),将会出现 TypeError: tuple expected at most 1 argument, got 2 的错误提示。 - undefined
这取决于你是关注遗留支持还是未来的持久性。你越早转移到新的规范形式,你的代码就越早为将来的升级做好准备,在那时旧的形式将被弃用。当然,你应该决定使用哪个版本的Python,并使用该版本。为什么要部署Python 3.10,却仍然使用Python 3.8编码呢? - NeilG

3

简而言之:

从Python 3.9开始,像ListTupleDict等类型别名已被弃用

因此,从那时起,请使用内置类型listtupledict等。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接