python - 在 Python 中键入没有赋值的提示

标签 python annotations type-hinting python-typing

我的印象是typing Python 中的模块主要用于提高代码可读性和代码文档目的。

在试用它并阅读了有关该模块的信息后,我设法将自己与它搞混了。

即使这两个变量未初始化(如您通常初始化它们,例如 a = "test"),下面的代码仍然有效。

我只在上面放了一个类型提示,一切似乎都正常。也就是说,我没有得到 NameError,如果我的代码中只有 a NameError: name 'a' is not defined

以这种方式(带有类型提示)声明变量是否可行?为什么会这样?

from typing import Any

test_var: int
a: Any

print('hi')

我希望 test_var: int 返回一个错误,指出 test_var 未启动,我必须执行类似 test_var: int = 0(或任何值)。这是否因为我向其添加了类型提示而设置为默认值?

最佳答案

当您考虑所涉及的 namespace 时,这非常简单。当您实际尝试使用 test_var 执行任何操作时,例如将其传递给函数(如 print )。它告诉您解释器不知道您使用的名称

变量赋值有什么作用?

当您第一次为模块的全局命名空间中的变量赋值时,会发生什么情况,它是否被添加到该模块 globals 字典中,键是变量名,并且值(value)就是它的值(value)。您可以通过调用内置的 globals 来查看此词典。该模块中的函数:

from pprint import pprint

a = 1

pprint(globals())

输出看起来像这样:

{'__annotations__': {},
 ...
 '__name__': '__main__',
 ...
 'a': 1,
 ...}

注解有什么作用?

当您仔细查看该词典时,您会发现另一个有趣的键,即 __annotations__。现在,它的值是一个空字典。但我打赌你已经猜到了,如果我们用类型注释我们的变量会发生什么:

from pprint import pprint

a: int = 1

pprint(globals())

输出:

{'__annotations__': {'a': <class 'int'>},
 ...
 'a': 1,
 ...}

当我们向变量添加类型提示(即注释)时,解释器会将该名称和类型添加到相关的__annotations__ 字典中(参见docs);在这种情况下,我们的模块。顺便说一下,由于 __annotations__ 字典在我们的全局命名空间中,我们可以直接访问它:

a: int = 1

print("a" in globals())        # True
print("a" in __annotations__)  # True

你能在不赋值的情况下进行注释吗?

最后,如果我们只是注释而不给变量赋值,会发​​生什么?

a: int

print("a" in globals())        # False
print("a" in __annotations__)  # True

这就是为什么我们会收到错误的解释,如果我们尝试,例如在此示例中打印出 a,否则不会出现任何错误。代码只是告诉解释器(和任何静态类型检查器)注释,但它没有分配任何值,因此无法在全局命名空间字典中创建条目。

如果您考虑一下,这是有道理的:应该在该命名空间中设置什么作为 a 的值?它没有任何值(value)(甚至没有 NoneNotImplemented 或类似的东西)。对于解释器而言,a: int 行仅仅意味着在我们模块的 __annotations__ 中创建一个条目,这是完全有效的。

注解的运行时含义

我还想强调一个事实,正如某些人经常声称的那样,注释对于解释器和运行时来说并非毫无意义。诚然,它很少被使用,但正如我们刚刚在示例中看到的,您绝对可以在运行时使用注释。这是否有用显然取决于您。一些包像 Pydantic或标准库的 dataclasses实际上,他们的目的严重依赖注释。

在我们的示例中,__annotations__ 字典中设置的值实际上是int 类的引用。所以我们完全可以在运行时使用它,如果我们想:

a: int

a_type = __annotations__["a"]
print(a_type is int)  # True
print(a_type("2"))    # 2

您也可以在类命名空间中尝试这个概念(不仅仅是模块命名空间),但我将把它留给读者作为练习。

总而言之,要将一个名称添加到任何命名空间,它必须有一个分配给它的值。 分配一个值,只提供一个注释就可以在该命名空间的 __annotations__ 中创建一个条目。

关于python - 在 Python 中键入没有赋值的提示,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74308012/

相关文章:

java - aspectj 中注释的优先顺序

swift - 将注释更改为引脚

python - 哪一种是在 Django 模型中使用 Python 类型提示的正确方法?

python - Python 2 中的类型提示

python - 在 pydantic 模型中包含非验证方法是不好的做法吗?

python - Matplotlib 累积图

python - Tkinter/Python 和 Arduino

python - 改组 SQLAlchemy 结果?

java - 向 Jersey multipart-form-data 函数添​​加注释会破坏它

python - python 类型注释中的链式引用