Python 如何键入以可调用函数及其参数为参数的函数,例如函数的数值积分? 问题
我有以下功能(基于): 。。。它基本上在一个值范围内计算Python 如何键入以可调用函数及其参数为参数的函数,例如函数的数值积分? 问题,python,generics,mypy,python-3.10,Python,Generics,Mypy,Python 3.10,我有以下功能(基于): 。。。它基本上在一个值范围内计算func,并使用固定宽度的条带计算图形下的面积。或者,可以通过args元组将参数传递给func 正如您所看到的,我已经做了一些初始类型提示(实际上这是scipy的.pyi存根),但是我不喜欢func&args的类型太松散。我想让mypy保护我免受两件事的伤害: func是一个可调用的函数,它必须具有第一个位置参数,即float,并返回float,还可以具有可选的*参数 i、 e.f(x:float,…)->至少是float 我猜它也可以有
func
,并使用固定宽度的条带计算图形下的面积。或者,可以通过args
元组将参数传递给func
正如您所看到的,我已经做了一些初始类型提示(实际上这是scipy的.pyi存根),但是我不喜欢func&args的类型太松散。我想让mypy保护我免受两件事的伤害:
func
是一个可调用的函数,它必须具有第一个位置参数,即float
,并返回float
,还可以具有可选的*参数
- i、 e.
f(x:float,…)->至少是float
- 我猜它也可以有**kwargs(尽管不能有或需要x以外的位置参数)
*args
到func
必须与飞溅的args元组的内容匹配例子
我试过的 对于
func
我尝试使用协议和泛型:
class OneDimensionalFunction(Protocol, Generic[T]): #double inheritance, although maybe I can get by with a metaclass for Generic
def __call__(self, x: float, *args: T) -> float: ...
。。。希望我能写作
def simple_quad(func: OneDimensionalFunction[T], a: float, b: float, args: tuple[T] = ()) -> float:
simple_quad(cubic, 1, 10, 10, (1,2,3,4)) # infer type requirement of args based on signature of func
# or
simple_quad[float,float,float,float](cubic, ...) #pass in additional type info above and beyond the expected Callable[[x:float,...], float]
。。。我知道这有很多问题,而且如果我想将lambda作为func传入,协议也不能很好地处理Callable
我将这个python标记为3.10,因为我认为新版本可能会有所帮助,但我只见过那些在装饰器中使用的,所以我不确定如何在这里应用它们。让我知道你的想法对协议使用重载。这不太好,但它让你尽可能接近真实的验证
from typing import Protocol, Tuple, Any, overload, Union, Optional
class C1(Protocol):
def __call__(self, a: float, ) -> float: ...
class C2(Protocol):
def __call__(self, a: float, b: float, ) -> float: ...
class C3(Protocol):
def __call__(self, a: float, b: float, c: float) -> float: ...
ET = Tuple[()]
T1 = Tuple[float]
T2 = Tuple[float, float]
T3 = Tuple[float, float, float]
@overload
def quad(func: C1, a: float, b: float, args: Union[ET, T1] = ()) -> float: ...
@overload
def quad(func: C2, a: float, b: float, args: Union[ET, T2] = ()) -> float: ...
@overload
def quad(func: C3, a: float, b: float, args: Union[ET, T3] = ()) -> float: ...
def quad(func: Any, a: float, b: float, args: tuple = ()) -> float:
return 0
def cubic(a: float, b: float, c: float, *, s: Optional[str] = None) -> float:
return 0
quad(cubic, 0, 1)
@OlvinRoght这是一个棘手的问题,我担心这样的逻辑不属于类型提示。这应该是一个运行时验证。@rdas我不知道,这感觉像是一个非常简单的方法,通过将不兼容的参数传递给函数来攻击自己。这仅仅是因为通过包装器函数进行了额外的重定向,所以键入变得复杂,如果func是functools.partial,我认为这会更容易(但不能是因为scipy也接受需要单独参数的低级可调用项)。我还认为,至少在这类问题上增加了一些新的内容;键入提示*args可调用参数到装饰器。键入提示不会阻止您自食其果。在强类型语言中,解决方案是为
args
定义一个类型&使用该类型。尝试用类型提示做类似的事情——假设可能的话——将是一个丑陋且无法维护的IMO。是什么让你认为它会有kwargs?
def simple_quad(func: OneDimensionalFunction[T], a: float, b: float, args: tuple[T] = ()) -> float:
simple_quad(cubic, 1, 10, 10, (1,2,3,4)) # infer type requirement of args based on signature of func
# or
simple_quad[float,float,float,float](cubic, ...) #pass in additional type info above and beyond the expected Callable[[x:float,...], float]
from typing import Protocol, Tuple, Any, overload, Union, Optional
class C1(Protocol):
def __call__(self, a: float, ) -> float: ...
class C2(Protocol):
def __call__(self, a: float, b: float, ) -> float: ...
class C3(Protocol):
def __call__(self, a: float, b: float, c: float) -> float: ...
ET = Tuple[()]
T1 = Tuple[float]
T2 = Tuple[float, float]
T3 = Tuple[float, float, float]
@overload
def quad(func: C1, a: float, b: float, args: Union[ET, T1] = ()) -> float: ...
@overload
def quad(func: C2, a: float, b: float, args: Union[ET, T2] = ()) -> float: ...
@overload
def quad(func: C3, a: float, b: float, args: Union[ET, T3] = ()) -> float: ...
def quad(func: Any, a: float, b: float, args: tuple = ()) -> float:
return 0
def cubic(a: float, b: float, c: float, *, s: Optional[str] = None) -> float:
return 0
quad(cubic, 0, 1)