我的印象是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)(甚至没有 None
或 NotImplemented
或类似的东西)。对于解释器而言,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/