问题
我有以下功能(基于scipy.integrate.quad
):
def simple_quad(func: Any, a: float, b: float, args: tuple = ()) -> float:
def strips(n: int):
for i in range(n):
x = a + (b - a) * i / n
yield func(x, *args) * 1 / n
return sum(strips(1000))
...它基本上评估func
一系列值并使用固定宽度的条带来计算图形下的面积。可选地,可以通过func
元组传递参数args
。
如您所见,我已经完成了一些初始类型提示(实际上这是 scipy 的 .pyi 存根),但是我对 func 和 args 的类型如此松散感到不满意。我希望 mypy 保护我免受两件事的影响:
func
是一个可调用的,它必须有一个第一个位置参数,它是 afloat
,并返回 afloat
,并且可以有可选的*args
- 即
f(x:float, ...) -> float
至少 - 我猜它也可以有 **kwargs (虽然不能有必需的名称参数或除了 x 以外的必需的位置参数)
- 即
- 可选的位置
*args
必须匹配func
splatted args 元组的内容
例子
def cubic(x: float, a: float, b: float, c: float, d: float) -> float:
"Function to evaluate a cubic polynomial with coefficients"
return a + b * x + c * x ** 2 + d * x ** 3
simple_quad(cubic, a=1, b=10, args=(1, 2, 3, 4)) # fine, passes args to a,b,c,d and int is compatible with float signature
simple_quad(cubic, a=1, b=10) # error from mypy as *args to `cubic` don't have default args so are all required
simple_quad(cubic, a=1, b=10, args=("a", "b", "c", "d")) # arg length correct but type mismatch since cubic expects floats
x_squared: Callable[[float], float] = lambda x: x * x
simple_quad(x_squared, a=1, b=10, args=()) # should be fine as x_squared doesn't take any positional args other than x
def problematic(x: float, *, y: float) -> float: ... # can't pass kwargs y via simple_quad, so can't be integrated
我试过的
因为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 传递,Protocol 也不能很好地与 Callable 配合使用。
我将这个 python 3.10 标记为我认为新的参数规范变量可能会有所帮助,但我只看到了装饰器中使用的那些,所以我不确定如何在这里应用它们。让我知道你的想法