具有不同 kwargs 的函数的回调协议

Abh*_*ury 3 python callback type-hinting python-3.x python-typing

我有一个将callback函数作为参数的函数:

def function(arg1: int, callback):
    ...
Run Code Online (Sandbox Code Playgroud)

我正在尝试为该函数添加类型提示callback。现在,传递给该函数的回调函数具有相同的位置参数,但 kwargs 可以完全不同(类型和名称)。

def function1(arg1: int, arg2: str, **kwargs1):
    ...

def function2(arg1: int, arg2: str, **kwargs2):
    ...
Run Code Online (Sandbox Code Playgroud)

我正在尝试编写一个适合这两个函数的回调协议,但到目前为止,我还没有找到一种方法可以在 kwargs 不同时使其工作。在这种情况下有没有办法创建统一的回调协议?

Mar*_*hac 6

您可以创建此回调协议:

from typing_extensions import Protocol


class Callback(Protocol):
    def __call__(self, arg1: int, arg2: str, **kwargs): ...
Run Code Online (Sandbox Code Playgroud)

并输入callback提示Callback

def function(arg1: int, callback: Callback): ...
Run Code Online (Sandbox Code Playgroud)

现在,在这三个函数调用中:

def function1(arg1: int, arg2: str, **kwargs1): ...
def function2(arg1: int, arg2: str, **kwargs2): ...
def function3(arg1: int): ...

function(0, function1) # Success.
function(0, function2) # Success.
function(0, function3) # Error.
Run Code Online (Sandbox Code Playgroud)

mypy将报告前两个成功,但由于缺少arg2.

这里要认识到的关键是关键字参数参数的名称实际上并不重要。如果我将function2其重命名arg1arg_1mypy会对此抱怨。这是因为 的公共接口function2已以向后不兼容的方式更改。例如,我必须arg1=0在任何调用站点修改arg_1=0.

但如果我采用相同的函数并重命名kwargs2kwargs_2,公共接口实际上并没有改变!这是因为首先不可能在调用站点显式引用kwargs//参数。举个例子:kwargs1kwargs2

function2(arg1=0, arg2="", kwargs2={})
Run Code Online (Sandbox Code Playgroud)

kwargs2如果我要从函数内部转储,它实际上会将键"kwargs2"映射到{},而不是本身是一个空字典。这表明不可能依赖关键字参数参数的名称。mypy因此,在检查 的公共接口是否function2与 的公共接口匹配时可以允许不同的名称Callback

至于类型,kwargs、 、kwargs1kwargs2都有左侧注释的类型Dict[str, Any]。由于您在所有 3 个方面保持一致,因此mypy此处报告成功,同时还使您能够利用特定于orAny的关键字参数。function1function2