Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/308.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何键入以可调用函数及其参数为参数的函数,例如函数的数值积分? 问题_Python_Generics_Mypy_Python 3.10 - Fatal编程技术网

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)