如何使用可选导入输入提示?
How to type hint with an optional import?
当使用可选的导入时,即包只在一个函数中导入,因为我希望它成为我的包的可选依赖项,有没有办法输入提示作为属于此可选依赖项的 类 之一的函数的 return 类型?
举一个简单的例子,把pandas
作为一个可选的依赖:
def my_func() -> pd.DataFrame:
import pandas as pd
return pd.DataFrame()
df = my_func()
在这种情况下,由于 import
语句在 my_func
内,因此这段代码将毫不奇怪地引发:
NameError: name 'pd' is not defined
如果使用字符串文字类型提示,即:
def my_func() -> 'pd.DataFrame':
import pandas as pd
return pd.DataFrame()
df = my_func()
模块现在可以正常执行,但是mypy
会报错:
error: Name 'pd' is not defined
如何使模块成功执行并保留静态类型检查功能,同时使此导入成为可选的?
尝试将您的导入粘贴到文件顶部的 if typing.TYPE_CHECKING
语句中。此变量在运行时始终为 false,但出于类型提示的目的而被视为始终为 true。
例如:
# 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()
您也可以 if False:
,但我认为这会让别人更难分辨发生了什么。
需要注意的是,这确实意味着虽然 pandas 将是运行时的可选依赖项,但出于类型检查的目的,它仍然是强制性依赖项。
您可以探索使用的另一个选项是 mypy 的 --always-true
and --always-false
标志。这会让您更细粒度地控制代码的哪些部分需要进行类型检查。例如,您可以这样做:
try:
import pandas as pd
PANDAS_EXISTS = True
except ImportError:
PANDAS_EXISTS = False
if PANDAS_EXISTS:
def my_func() -> pd.DataFrame:
return pd.DataFrame()
...然后执行 mypy --always-true=PANDAS_EXISTS your_code.py
进行类型检查,假设 pandas 已导入,mypy --always-false=PANDAS_EXISTS your_code.py
进行类型检查,假设它丢失。
这可以帮助您发现您不小心使用了一个需要 pandas 的函数,而这个函数本不应该需要它——尽管需要注意的是 (a) 这是一个 mypy-唯一的解决方案和 (b) 具有仅有时存在于您的库中的功能可能会让最终用户感到困惑。
这是我暂时使用的解决方案,虽然我还没有尝试过 MyPy,但它似乎在 PyCharm 的 type-checker 中有效。
from typing import TypeVar, TYPE_CHECKING
PANDAS_CONFIRMED = False
if TYPE_CHECKING:
try:
import pandas as pd
PANDAS_CONFIRMED = True
except ImportError:
pass
if PANDAS_CONFIRMED:
DataFrameType = pd.DataFrame
else:
DataFrameType = TypeVar('DataFrameType')
def my_func() -> DataFrameType:
import pandas as pd
return pd.DataFrame()
这具有始终定义函数的优势(因此,如果有人运行调用 my_func
的代码,他们将得到一个信息丰富的 ImportError,而不是误导性的 AttributeError)。即使未安装 pandas,这也总是提供某种 type-hint,而不会在运行时过早地尝试导入 pandas。 if-else 结构使 PyCharm 将 DataFrameType
的某些实例视为 Union[DataFrame, DataFrameType]
但它仍然提供数据帧的 well-suited linting 信息,在某些情况下,就像 my_func
的输出一样,它以某种方式推断出 DataFrameType 实例将始终是 DataFrame。
当使用可选的导入时,即包只在一个函数中导入,因为我希望它成为我的包的可选依赖项,有没有办法输入提示作为属于此可选依赖项的 类 之一的函数的 return 类型?
举一个简单的例子,把pandas
作为一个可选的依赖:
def my_func() -> pd.DataFrame:
import pandas as pd
return pd.DataFrame()
df = my_func()
在这种情况下,由于 import
语句在 my_func
内,因此这段代码将毫不奇怪地引发:
NameError: name 'pd' is not defined
如果使用字符串文字类型提示,即:
def my_func() -> 'pd.DataFrame':
import pandas as pd
return pd.DataFrame()
df = my_func()
模块现在可以正常执行,但是mypy
会报错:
error: Name 'pd' is not defined
如何使模块成功执行并保留静态类型检查功能,同时使此导入成为可选的?
尝试将您的导入粘贴到文件顶部的 if typing.TYPE_CHECKING
语句中。此变量在运行时始终为 false,但出于类型提示的目的而被视为始终为 true。
例如:
# 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()
您也可以 if False:
,但我认为这会让别人更难分辨发生了什么。
需要注意的是,这确实意味着虽然 pandas 将是运行时的可选依赖项,但出于类型检查的目的,它仍然是强制性依赖项。
您可以探索使用的另一个选项是 mypy 的 --always-true
and --always-false
标志。这会让您更细粒度地控制代码的哪些部分需要进行类型检查。例如,您可以这样做:
try:
import pandas as pd
PANDAS_EXISTS = True
except ImportError:
PANDAS_EXISTS = False
if PANDAS_EXISTS:
def my_func() -> pd.DataFrame:
return pd.DataFrame()
...然后执行 mypy --always-true=PANDAS_EXISTS your_code.py
进行类型检查,假设 pandas 已导入,mypy --always-false=PANDAS_EXISTS your_code.py
进行类型检查,假设它丢失。
这可以帮助您发现您不小心使用了一个需要 pandas 的函数,而这个函数本不应该需要它——尽管需要注意的是 (a) 这是一个 mypy-唯一的解决方案和 (b) 具有仅有时存在于您的库中的功能可能会让最终用户感到困惑。
这是我暂时使用的解决方案,虽然我还没有尝试过 MyPy,但它似乎在 PyCharm 的 type-checker 中有效。
from typing import TypeVar, TYPE_CHECKING
PANDAS_CONFIRMED = False
if TYPE_CHECKING:
try:
import pandas as pd
PANDAS_CONFIRMED = True
except ImportError:
pass
if PANDAS_CONFIRMED:
DataFrameType = pd.DataFrame
else:
DataFrameType = TypeVar('DataFrameType')
def my_func() -> DataFrameType:
import pandas as pd
return pd.DataFrame()
这具有始终定义函数的优势(因此,如果有人运行调用 my_func
的代码,他们将得到一个信息丰富的 ImportError,而不是误导性的 AttributeError)。即使未安装 pandas,这也总是提供某种 type-hint,而不会在运行时过早地尝试导入 pandas。 if-else 结构使 PyCharm 将 DataFrameType
的某些实例视为 Union[DataFrame, DataFrameType]
但它仍然提供数据帧的 well-suited linting 信息,在某些情况下,就像 my_func
的输出一样,它以某种方式推断出 DataFrameType 实例将始终是 DataFrame。