Python:类型注释,如何定义元组的元素?

19

这里是一个最小的示例。

def foo(x:int, y:int) -> tuple: 
    return (x*y, y//2)

-> tuple(:int, :int)这样的格式非常诱人,但实际上它是无效的。在这种情况下是否有正确的方法,或者直到Python进一步推广类型注释之前它仍然是一个灰色地带?

编辑: 显然可以做类似的事情。

def bar(x, y) -> ((str, int), (str, int)): 
     return ("%s+%s" %(x,y), x+y), ("%s-%s" %(x,y), x-y) 

请查看相关的 PEP,该文档最近得到了很多进展。如果你真的很好奇,也可以查看 python-ideas 邮件列表存档,Guido 在 2015 年 1 月中旬发起了一篇关于这个 PEP 的主题讨论。 - John Y
自从 Python 3.9 PEP 585 版本以后,我们可以编写 tuple[int, int]。 - Viljami
3个回答

36

现在有一种方法可以对这个案例进行注释:

from typing import Tuple
def foo(x:int, y:int) -> Tuple[int, int]: 
    return (x*y, y//2)

注意: Python运行时不会抱怨-> (int, int),但这并不是PEP 484规定的正确类型注释。换句话说,如果您想使用类型提示创建自己的小型语言,则可以使用它;但它不被 Python 类型标准(PEP 484)所接受。


如何给 [[str, int]] 加注解?即使元素 [str, int] 是类似于 List[Tuple[str,int]] 的列表,我能否使用 Tuple? - droid192
1
@qrtLs 不可以。Python类型注释只能表示所有项具有相同类型的列表。无法说明my_list是一个包含两个strint类型的列表。原因:变量不能更改其类型,而列表更改其长度非常常见。如果长度可以更改,并且项目类型不同,则不清楚当用户尝试将int附加到List[int,str]时类型系统应该做什么。所选择的解决方案是根本不能指定长度,并且所有项的类型必须相同。 - max
@qrtLs 但是你可以,也许应该在返回值中使用一个实际的元组:如果列表始终是两个元素,并且它们始终具有相同的类型,那么为什么一开始就是一个列表呢?为了使接收它的函数更容易对其进行变异吗?在你的情况下,这是足够强的理由吗? - mtraceur
自Python 3.9 PEP 585起,我们可以编写tuple[int, int]。 - Viljami

3
编辑(2023年):尽管此答案在发布时很有用,现在仍具有历史意义,但其建议现在已经过时、误导和有害。其他答案已经提到自此发布以来PEP-484正式化了不同的语法。

目前还没有一种规范的方法来实现这一点。Python类型注释是语言的一个相对较新的补充,因此它们仍然有些局限性。

目前,您可以使用元组字面量:

def foo(x:int, y:int) -> (int, int):
    return (x*y, y//2)

那么,或者一个字符串字面量,例如:
def foo(x:int, y:int) -> 'tuple(int, int)':
    return (x*y, y//2)

这两个都非常清楚地表达了你的意图。


2
嗯,我并不太热衷于这个。这违背了Python动态类型的初衷,并破坏了该语言的一项重要功能。我的意思是,如果你想要静态类型,为什么不使用Java或C++(它们通常更快)?Python之所以伟大,是因为它具有动态性。当然,这只是我的观点。 :) - user2555451
我应该澄清一下,我只是指规定(在已注释的代码上)——我觉得很奇怪,我可以写def foo() -> int:并返回一个str;尽管这可能不经常发生;但def foo() -> int返回一个float可能确实发生。 - user3467349
考虑到PEP 484的最新发展,这个答案可能有点过时了。请看一下我对问题提出者的评论。 - John Y
@user3467349:正如我们所知道的,Python永远不会强制使用静态类型。这就是Python的特性所在。如果您跟踪Python的开发,您会深刻感受到Guido和核心开发人员对这些注释的坚持,而不是声明。但是,如果您喜欢静态类型,或者甚至是具有可选的、挑选性的静态类型的混合系统,那么除了Python之外,还有其他选择。最容易想到的两个是Cython和Nim(以前是Nimrod),它们绝不是唯一的选择。 - John Y
@JohnY 如果你的意思是我喜欢Julia中的静态类型,那么我非常喜欢(尽管我对它与Julia风格的动态分派交互方式不太满意)。但是,是的,我认为在使用静态类型的代码中不强制执行静态类型没有任何优势,这只会导致简单的不正确注释,实际上比没有注释更糟糕。 - user3467349
显示剩余4条评论

1

typing.Tuple 在 Python 3.9 中已被弃用。您应该使用内置的 tuple 类型代替(无需导入):

def foo(x:int, y:int) -> tuple[int, int]: 
    return (x*y, y//2)

typing.Tuple文档中说明:

自3.9版本起已弃用: builtins.tuple现在支持下标([])。请参见PEP 585通用别名类型


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