首页 > 解决方案 > 具有不同 kwargs 的函数的回调协议

问题描述

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

def function(arg1: int, callback):
    ...

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

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

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

我正在尝试编写一个适合这两个函数的回调协议,但到目前为止,当 kwarg 不同时,我还没有看到一种方法来完成这项工作。在这种情况下有没有办法创建统一的回调协议?

标签: pythonpython-3.xcallbacktype-hintingpython-typing

解决方案


您可以创建此回调协议:

from typing_extensions import Protocol


class Callback(Protocol):
    def __call__(self, arg1: int, arg2: str, **kwargs): ...

并输入提示callbackCallback

def function(arg1: int, callback: Callback): ...

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

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.

mypy前两个会报成功,第三个会报错,因为缺少arg2.

这里要意识到的关键是关键字参数的名称实际上并不重要。如果我接受function2并重命名arg1arg_1mypy会抱怨这一点。这是因为 的公共接口function2以向后不兼容的方式发生了变化。例如,我必须arg1=0在任何呼叫站点修改为arg_1=0.

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

function2(arg1=0, arg2="", kwargs2={})

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

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


推荐阅读