如何使用可选导入输入提示?

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)具有以下功能:仅有时存在于您的库中可能会让最终用户感到困惑。