dsp*_*cer 6 python mypy python-typing
当使用可选导入时,即包仅在函数内部导入,因为我希望它成为我包的可选依赖项,有没有办法将函数的返回类型提示为属于此可选的类之一依赖?
举一个简单的例子,pandas作为一个可选的依赖:
def my_func() -> pd.DataFrame:
import pandas as pd
return pd.DataFrame()
df = my_func()
Run Code Online (Sandbox Code Playgroud)
在这种情况下,由于import语句在 内my_func,因此该代码将毫不奇怪地引发:
NameError: 名称 'pd' 未定义
如果改为使用字符串文字类型提示,即:
def my_func() -> 'pd.DataFrame':
import pandas as pd
return pd.DataFrame()
df = my_func()
Run Code Online (Sandbox Code Playgroud)
该模块现在可以毫无问题地执行,但mypy会抱怨:
错误:未定义名称“pd”
如何使模块成功执行并保留静态类型检查功能,同时还可以选择此导入?
Mic*_*x2a 14
尝试将导入内容粘贴到if typing.TYPE_CHECKING文件顶部的语句中。该变量在运行时始终为假,但出于类型提示的目的被视为始终为真。
例如:
# Lets us avoid needing to use forward references everywhere
# for Python 3.7+
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
import pandas as pd
def my_func() -> pd.DataFrame:
import pandas as pd
return pd.DataFrame()
Run Code Online (Sandbox Code Playgroud)
你也可以这样做if False:,但我认为这会让人们更难说出发生了什么。
需要注意的是,这确实意味着虽然 pandas 在运行时将是一种可选依赖项,但出于类型检查的目的,它仍然是强制性依赖项。
您可以探索使用的另一个选项是 mypy's--always-true和--always-falseflags。这将使您能够更细粒度地控制对代码的哪些部分进行类型检查。例如,你可以这样做:
try:
import pandas as pd
PANDAS_EXISTS = True
except ImportError:
PANDAS_EXISTS = False
if PANDAS_EXISTS:
def my_func() -> pd.DataFrame:
return pd.DataFrame()
Run Code Online (Sandbox Code Playgroud)
...然后进行mypy --always-true=PANDAS_EXISTS your_code.py类型检查,假设 pandas 已导入,并mypy --always-false=PANDAS_EXISTS your_code.py进行类型检查,假设它丢失。
这可以帮助您发现意外使用需要 pandas 的函数的情况,而该函数并不需要它——尽管需要注意的是(a)这是一个仅限 mypy 的解决方案,并且(b)具有以下功能:仅有时存在于您的库中可能会让最终用户感到困惑。