作为函数声明中的参数类型

3
如果您需要在Python中指定参数类型,例如我的例子中的数组,您需要编写以下代码:
def my_function(param: list):
    pass

在Swift中,您可以像这样指定参数类型:
func myFunction(param: [Any]) {
//
}

有一天,我犯了Swift风格的错误,写成了:

def my_function_2(param: []):
    pass

现在我注意到了一些奇怪的东西并尝试了一些更奇怪的事情:

def my_function_3(param: 1):
    pass

所有这些函数都是有效的,可以在Python 3.6中调用。带有期望参数类型one的函数...为什么会这样,为什么我看不到任何警告,我需要传递什么样的变量给函数2和3来满足我错误地请求的参数类型?

1个回答

9

Python的编译器和解释器对注释没有任何意义。1只要你输入的是语法上有效的表达式,Python就会计算它,并将它的值作为函数注释的一部分存储下来,供你随意使用(通常情况下不做任何事情)。

实际上,你可以看到它被存储了:

>>> print(my_function_3.__annotations__)
{'param': 1}

注释的主要目的是为了使用静态类型检查器,正如在PEP 484(以及相关的PEP 483PEP 482)中所解释的那样。

在Python中,静态类型检查是可选的,并且通常使用专用工具(如mypy)或集成到IDE(如PyCharm)中的工具来完成。

如果您对代码运行这样的检查器,它会发出警告。例如:

$ mypy testscript.py
testscript.py:1: error: invalid type comment or annotation

这个错误意味着它无法确定 1 应该是什么类型。2
最后一件事:

我需要传递哪种类型的变量给函数2和3,以满足我错误地请求的参数类型?

没有任何类型能够满足这个要求。Python 的运行时类型规则比其(可选的)静态类型规则更灵活,但它们并不是那么灵活。3
1. 然而,它们对 stdlib 中至少一个东西有意义,即dataclass 装饰器 2. Mypy 从这里继续执行,但没有更多的错误,即使你在函数体中滥用参数或不正确地调用函数。据我所知,它跳过了对函数体的检查,并将函数视为接受任何参数并返回 Any 的函数。这相当合理——这样你只会得到这一个错误,而不是数百个毫无意义的错误。 3. 你甚至无法测试它——isinstance(obj, 1) 会引发异常,因为 1 不是 type 的实例。但如果你能这样做,它只能在调用 1(或 1 的子类,没有子类)作为元类创建 obj 或将 obj.__class__ 设置为 1(或其子类),或者如果 int 有一个接受 obj 的实例或子类挂钩,那么它才会返回 true,但是它是不可能的。但是——至少在 CPython 和 PyPy 中——甚至无法达到那一步。当然,你可以直接修改 obj 下面的结构体中的 ob_type 字段,让它指向 1 对象,但如果你这样做,任何你尝试对 obj 做的事情都会导致 segfault。

你提到了 PyCharm - 我在使用它。而且这两个函数(2 和 3)都没有任何警告。 - Stanislav Chernischuk
@StanislavChernischuk 我没有用过它。我知道它声称拥有集成的静态类型检查器,但我并不知道更多信息。 - abarnert
@StanislavChernischuk 从快速搜索中,我找到了这个链接,但它似乎更多地涉及使用PyCharm添加和管理类型提示,而不是使用它来检查它们。对于这一点,我无法再为您提供更多帮助(但如果您想要帮助将mypy添加到您的emacs fly-check中...)。 - abarnert
无论如何,这对我来说是非常有用的参考。我也不知道 mypy。所有这些都会对我有很大帮助! - Stanislav Chernischuk

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