如何使用 *args 和 **kwargs 注释可调用对象?

How do I annotate a callable with *args and **kwargs?

我有一个函数其中returns一个函数。我想找到一个合适的类型注释。但是,返回的函数有*args*kwargs。在 Callable[[Parameters???], ReturnType] 中如何注释?

示例:

from typing import Callable
import io
import pandas as pd

def get_conversion_function(file_type: str) -> Callable[[io.BytesIO, TODO], pd.DataFrame]:
    def to_csv(bytes_, *args, **kwargs):
        return pd.read_csv(bytes_, **kwargs)
    if file_type == "csv":
        return to_csv

据我所知,python 的输入不允许直接按照 typing.Callable 的文档中所述进行操作:

There is no syntax to indicate optional or keyword arguments; such function types are rarely used as callback types. Callable[..., ReturnType] (literal ellipsis) can be used to type hint a callable taking any number of arguments and returning ReturnType.

但你可以这样使用 mypy extensions

from typing import Callable
from mypy_extensions import Arg, VarArg, KwArg

def foo(a: str, *args: int, **kwargs: float) -> str:
    return 'Hello, {}'.format(a)
    
def bar() -> Callable[[Arg(str, 'a'), VarArg(int), KwArg(float)], str]:
    return foo

随着 typing.Protocol 的引入,MyPy(和其他兼容的类型检查器)通过 __call__ 特殊方法原生支持完整的调用语法。

MyPy: Callback Protocols

Protocols can be used to define flexible callback types that are hard (or even impossible) to express using the Callable[...] syntax, such as variadic, overloaded, and complex generic callbacks. (...)

简单地定义一个 Protocol__call__ 方法具有所需的签名。

from typing import Protocol

class SomeCallable(Protocol):
      def __call__(self, a: str, b: int, *args: float, **kwargs: str) -> bytes: ...

def my_callable(a: str, b: int, *args: float, **kwargs: str) -> bytes:
    return b"Hello World"

def my_func(key: str) -> SomeCallable:
    return my_callable

请注意 Protocol__call__ 必须包含一个 self 参数。将其他签名与 Protocol.

进行比较时忽略此参数