Hen*_*yKo 2 type-hinting strong-typing pep python-3.7
进口有from __future__ import annotations什么好处?当我理解正确时,我应该在运行时停止不必要的输入导入。
在我的例子HelloWorld中只需要打字。但是使用此代码,输出始终为:
Should this happen?
x = World!
当我删除from hello import HelloWorldPyCharm 中的输入帮助时,它不再起作用(我可以理解这一点,因为它不知道从哪里来HelloWorld)。
from __future__ import annotations
from hello import HelloWorld
if __name__ == '__main__':
def hello(x: str, hello: HelloWorld = None):
if hello is not None:
print('hello.data_01 =', hello.data_01)
print('x =', x)
hello('World!')
Run Code Online (Sandbox Code Playgroud)
你好.py
from dataclasses import dataclass
@dataclass
class HelloWorld:
data_01: str
data_02: str
print("Should this happen?")
Run Code Online (Sandbox Code Playgroud)
所以我的问题是我是否仍然需要from hello import HelloWorld做我能从中得到什么好处from __future__ import annotations?
该from __future__ import annotations进口有一个核心优势:它使得使用向前引用清洁。
例如,考虑这个(当前损坏的)程序。
# Error! MyClass has not been defined yet in the global scope
def foo(x: MyClass) -> None:
pass
class MyClass:
# Error! MyClass is not defined yet, in the class scope
def return_copy(self) -> MyClass:
pass
Run Code Online (Sandbox Code Playgroud)
当您尝试在运行时运行该程序时,该程序实际上会崩溃:在实际定义它之前,您已经尝试使用 'MyClass'。为了之前解决这个问题,您必须使用类型注释语法或将每个“MyClass”包装在一个字符串中以创建前向引用:
def foo(x: "MyClass") -> None:
pass
class MyClass:
def return_copy(self) -> "MyClass":
pass
Run Code Online (Sandbox Code Playgroud)
虽然这有效,但感觉非常笨拙。类型应该是类型:我们不需要手动将某些类型转换为字符串,只是为了让类型与 Python 运行时很好地配合。
我们可以通过包含from __future__ import annotationsimport来解决这个问题:该行在运行时自动使所有类型成为字符串。这让我们可以编写看起来像第一个示例的代码而不会崩溃:因为每个类型提示在运行时实际上是一个字符串,我们不再引用尚不存在的东西。
而像 mypy 或 Pycharm 这样的类型检查器不会在意:对他们来说,无论 Python 本身选择如何表示类型,类型看起来都是一样的。
需要注意的一件事是,这个导入本身并不能让我们避免导入东西。这样做只是让它更干净。
例如,请考虑以下情况:
from expensive_to_import_module import MyType
def blah(x: MyType) -> None: ...
Run Code Online (Sandbox Code Playgroud)
如果expensive_to_import_module有很多启动逻辑,那可能意味着导入MyType. 一旦程序实际运行,这不会真正产生影响,但它确实会使启动时间变慢。如果您尝试编写短命的命令行风格程序,这会让您感觉特别糟糕:添加类型提示的行为有时会使您的程序在启动时感觉更加迟钝。
我们可以通过创建MyType一个字符串来解决这个问题,同时将导入隐藏在一个if TYPE_CHECKING守卫后面,像这样:
from typing import TYPE_CHECKING
# TYPE_CHECKING is False at runtime, but treated as True by type checkers.
# So the Python interpreters won't do the expensive import, but the type checker
# will still understand where MyType came from!
if TYPE_CHECKING:
from expensive_to_import_module import MyType
# This is a string reference, so we don't attempt to actually use MyType
# at runtime.
def blah(x: "MyType") -> None: ...
Run Code Online (Sandbox Code Playgroud)
这有效,但再次看起来笨重。为什么我们需要在最后一个类型周围添加引号?在annotations未来的进口使得这样做有点平滑的语法:
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from expensive_to_import_module import MyType
# Hooray, no more quotes!
def blah(x: MyType) -> None: ...
Run Code Online (Sandbox Code Playgroud)
根据您的观点,这似乎不是一个巨大的胜利。但它确实有助于使使用类型提示更符合人体工程学,使它们感觉更“集成”到 Python 中,并且(一旦默认启用这些提示)消除了 PEP 484 新手容易绊倒的常见绊脚石。