如何为 Python 类型提示定义实数的泛型类型

问题描述 投票:0回答:1

我正在尝试定义一个接受所有实数的自定义类型(用于Python类型提示)。实际上,我想支持任何允许有意义比较的数字类型,但坚持只使用实数就足够了。然而,我这样做的方式似乎并不正确。例如,使用以下代码片段:

import numbers
import typing

MyDataType = typing.NewType('MyDataType', numbers.Real)

def f(a : MyDataType) -> None:
    pass

f(5)

我的朋友抱怨说:

“f”的参数 1 具有不兼容的类型“int”;预期为“MyDataType”

我如何才能真正实现我想要做的事情?

python python-typing mypy
1个回答
0
投票

numbers
包中的类是抽象基类(ABC)(即无法实例化),类型
int
float
分别注册为
numbers.Integral
numbers.Real
的虚拟子类。注册虚拟子类允许
isinstance
issubclass
读取它(在 docs 中了解有关 ABC 的更多信息)。

>>> issubclass(int, numbers.Real)
True
>>> issubclass(float, numbers.Real)
True

但是,由于

int
float
已注册为虚拟子类,因此
mypy
目前无法将
int
float
解析为
numbers.Real
的有效子类,如访问
cls.__mro__
所示:

>>> int.__mro__
(<class 'int'>, <class 'object'>)
>>> float.__mro__
(<class 'float'>, <class 'object'>)
>>> numbers.Integral.__mro__
(<class 'numbers.Integral'>, <class 'numbers.Rational'>, <class 'numbers.Real'>, <class 'numbers.Complex'>, <class 'numbers.Number'>, <class 'object'>)
>>> numbers.Real.__mro__
(<class 'numbers.Real'>, <class 'numbers.Complex'>, <class 'numbers.Number'>, <class 'object'>)

在阅读了一大堆

mypy
代码后,似乎可能存在一个错误,即未将内置类型检查为虚拟子类。理论上,
mypy
应该将
int
float
识别为有效子类,并且可以使用
bound
中的
TypeVar
关键字来回答允许任何子类型的其他问题。

import numbers
import typing

MyDataType = typing.TypeVar('MyDataType', bound=numbers.Real)

def f(a: MyDataType) -> None:
    pass

f(5)  # in reality, mypy returns a type-var error since it cannot resolve "int" as a valid subclass of "numbers.Real"

要使用

int
float
类型(包括任何其他类型),请将每种类型添加为
TypeVar
的参数。

import typing

MyDataType = typing.TypeVar('MyDataType', int, float)

def f(a: MyDataType) -> None:
    pass

f(5)  # Success: no issues found in 1 source file

或者,如果您使用的是 Python 3.12,现在可以使用以下语法:


def f[T: int, float](a: T) -> None:
    pass

f(5)  # Success: no issues found in 1 source file

如果您想使用此语法,请确保在运行

--enable-incomplete-feature=NewGenericSyntax
时包含标志
mypy

© www.soinside.com 2019 - 2024. All rights reserved.