为什么使用' from module import A as A '而不是' from module import A

  • 本文关键字:module import from as python mypy
  • 更新时间 :
  • 英文 :


在阅读fastapi的源代码时,这一行让我很模糊:

from starlette.testclient import TestClient as TestClient

为什么不直接写:from starlette.testclient import TestClient

从可执行代码的角度来看,两个不同的代码示例(使用Python 3.9)生成的Python字节码绝对没有区别:

>>> dis.dis('from starlette.testclient import TestClient as TestClient')
1           0 LOAD_CONST               0 (0)
2 LOAD_CONST               1 (('TestClient',))
4 IMPORT_NAME              0 (starlette.testclient)
6 IMPORT_FROM              1 (TestClient)
8 STORE_NAME               1 (TestClient)
10 POP_TOP
12 LOAD_CONST               2 (None)
14 RETURN_VALUE
>>> dis.dis('from starlette.testclient import TestClient')
1           0 LOAD_CONST               0 (0)
2 LOAD_CONST               1 (('TestClient',))
4 IMPORT_NAME              0 (starlette.testclient)
6 IMPORT_FROM              1 (TestClient)
8 STORE_NAME               1 (TestClient)
10 POP_TOP
12 LOAD_CONST               2 (None)
14 RETURN_VALUE

如图所示,它们完全相同。(相关线程和线程)

然而,Graham501617的评论指出,现代类型提示验证器(如mypy)如何接受这种特定的语法来表示导入名称的重新导出(另一个是__all__,值得庆幸的是,他们最终正确支持,因为这是自Python 2以来表示要(重新)导出的符号的标准语法)。具体地说,根据参考PEP 0484中的Stub文件描述,引用:

  • 导入到存根的模块和变量不被认为是从存根导出的,除非导入使用import ... as ...形式或等效的from ... import ... as ...形式。(更新:为了澄清,这里的意图是只有使用X as X形式导入的名称才会被导出,即as之前和之后的名称必须相同。)

这意味着库可能遵循特定的约定,以方便从问题中引用的存根(模块)文件中重新导出TestClient名称。事实上,查看git blame中指向此提交的包中的相关文件(直接链接到该文件的相关diff),其中包含类似的简短讨论,以解决确切的类型提示问题;这样做是为了确保mypy将这些导入的名称视为重新导出,从而允许使用--no-implicit-reexport标志(--strict可能已隐式启用)。

最新更新