语境
我们开发了一个 Python 库,其中包含一个需要 numlike 参数的函数。我们在签名中指定这一点并使用 python 类型提示:
def cool(value: float | int | List[float | int])
🏳 问题与目标
在运行时,我们注意到传递 numpy 数字类型也很好,例如np.float16(1.2345)
。所以我们想:为什么不将“numpy 数字类型”合并到我们的签名中,因为这对使用我们库的社区是有益的。
但是,我们不希望numpy
在我们的项目中存在依赖关系。我们只想在方法签名中表示我们可以采用float
、int
、它们的列表或任何“numpy 数字类型”。如果用户尚未numpy
在他们的系统上安装,他们仍然应该能够使用我们的库,并且忽略他们也可能传递“numpy 数字类型”。
我们不想依赖它,numpy
因为我们不在我们的库中使用它(除了在我们的方法签名中允许它们的类型)。那么为什么要把它包含在我们的依赖图中呢?没有理由这样做。少一种依赖就更好了。
附加要求/背景
- 我们寻找与所有 Python 版本兼容的答案
>=3.8
。 - (答案应该适用于
setuptools>=69.0
。) - 答案应该是这样的:当我们在 IDE(例如 VSCode)中
Ctrl + Space
输入时,我们可以获得正确的 IntelliSense () 。cool(
- 就是我们的
pyproject.toml
样子。
努力
[project.optional-dependencies]
我们注意到该文件的选项pyproject.toml
,请参见。但是,目前尚不清楚此可选依赖项声明如何帮助我们numpy
在方法签名中提供可选数据类型。numpy
提供类型注释。是否有可能只依赖这个子包?- 我们在搜索引擎上进行了搜索并发现了,但是我们的问题更具体的是我们如何只能使用另一个模块中的类型。我们还发现了可选的numpy 类型无关。
3
1 个回答
1
推迟对注释的评估,并且仅有导入 numpy 。
from __future__ import annotations
import typing as t
if t.TYPE_CHECKING:
import numpy as np
def cool(value: int | np.floating | etc ...):
...
现在,仅在类型检查时才需要 numpy 依赖项。
请参阅
附带问题..
numpy
提供numpy.typing
类型注释。是否有可能只依赖这个子包?
不,这是不可能的。
[project.optional-dependencies]
我们注意到该文件的选项pyproject.toml
…
它在这里对你没有多大帮助。如果您想要用户可以选择加入的“额外”依赖项,它仍然很有用,例如:
pip install mypkg # install with required dependencies
pip install mypkg[typing] # install with extra dependencies such as numpy
例如,然后您可以使用它轻松安装该软件包以及 CI 中的软件依赖。
10
-
不过,使用
numbers.Number
会得到像decimal.Decimal
和 之类的东西fractions.Fraction
。 (它也会出现complex
– 你需要numbers.Real
排除它。)
– -
decimal.Decimal
不太可能没事。即使只是尝试添加0.5
到 adecimal.Decimal
也会产生TypeError
.。numbers.Number
如果不知道更具体的类型,您对实例几乎无能为力。
– -
不幸的是,对于选项 1,(以及 VSCode 中的 Pylance 语言服务器)给出了以下错误:
error: Argument of type "float16" cannot be assigned to parameter "param" of type "Real" in function "blablah". "float16" is incompatible with "Real" (reportArgumentType)
– -
Pyright 存储库中写下了这个问题。
– -
1或多或少评论让我意识到选项 1 不可行。
int
等float
实际上并不从numbers
类型继承,这些是虚拟子类,并且 isinstance 检查在运行时动态处理。静态类型检查器无法识别虚拟子类关系,并且没有计划在 mypy 或 Pyright 中支持这一点,也没有计划在 typeshed 中覆盖它。因此,数字塔numbers
ABC 仅对运行时类型检查器有用,对使用静态分析的类型检查器不起作用。
–
|
if TYPE_CHECKING:
避免循环导入的技巧吗?–
numpy
?当然,它很“大”,但只是对于 Python 包来说才大。从绝对意义上讲,就下载量和文件系统占用量而言,它基本上是非常小的。–
–
|