为需要 kwargs 的 Callable 键入提示

Posted

技术标签:

【中文标题】为需要 kwargs 的 Callable 键入提示【英文标题】:Type hint for Callable that takes kwargs 【发布时间】:2021-09-28 23:46:51 【问题描述】:

我想做类似的事情

from typing import Callable


def a(foo: Callable[[int], None]):
    foo(b=5)

此代码有效,但会发出警告Unexpected argument

定义为

def a(foo: Callable[[int], None]):
    foo(5)

按预期工作,没有警告。


如何将预期的参数作为 kwarg 传递给函数,而类型检查器不会生我的气?

【问题讨论】:

这更多是mypy (或任何向您发出警告的工具)的问题,而不是类型提示的问题。 将类型提示视为函数的数学属性,而不是反映 Python 中特定函数实现的语义的东西。 foo 接受一个整数参数;您是否提供参数作为位置参数或关键字参数对于静态类型检查无关紧要。 【参考方案1】:

你可以在这里使用“可调用协议”,所以:

import typing

class MyCallableType(typing.Protocol):
    def __call__(self, bar:int) -> None:
        ...

def a(foo: MyCallableType):
    foo(32)
    foo(bar=32)

现在,使用mypy 测试上述内容:

jarrivillaga$ mypy --version
mypy 0.910
jarrivillaga$ mypy test.py
Success: no issues found in 1 source file

注意,这允许 mypy 捕获各种错误,例如具有错误参数名称的函数,或者如果我们希望 b 成为指定仅关键字 bar 参数的函数:

import typing

class MyCallableType(typing.Protocol):
    def __call__(self, b:int) -> None:
        ...

def a(foo: MyCallableType):
    foo(32)
    foo(b=32)

def bar(b: int) -> None:
    pass

def baz(*, b: int) -> None:
    pass

def bing(x: int) -> None:
    pass

a(bar)
a(baz)
a(bing)

mypy 会抱怨以下内容:

jarrivillaga$ mypy test.py
test.py:21: error: Argument 1 to "a" has incompatible type "Callable[[NamedArg(int, 'b')], None]"; expected "MyCallableType"
test.py:22: error: Argument 1 to "a" has incompatible type "Callable[[int], None]"; expected "MyCallableType"
Found 2 errors in 1 file (checked 1 source file)

【讨论】:

这是正确的解决方案,但在我看来,定义一个新类型对于仅接受 int 的函数来说太过分了,这就是我选择... 解决方案的原因。 你能解释一下为什么需要定义一个新类型吗?毕竟,这并没有添加任何新的静态信息。 @Gulzar 仅仅是因为Callable 不支持任何方式来指示参数的名称或它们是关键字参数。我认为 mypy 正在开发允许它的扩展,但它们被放弃了,新的指导只是使用可调用协议。【参考方案2】:

Callabledocs说

没有指示可选或关键字参数的语法;此类函数类型很少用作回调类型。

不过他们也说

Callable[..., ReturnType](文字省略号)可用于键入提示一个可调用的参数,并返回任意数量的参数并返回 ReturnType

在这里申请,那就是

def a(foo: Callable[..., None]):

您将丢失 int 批注,但要么接受警告,要么明确超过警告。

【讨论】:

以上是关于为需要 kwargs 的 Callable 键入提示的主要内容,如果未能解决你的问题,请参考以下文章

如何将函数参数键入为本机函数

为啥我需要在 Django 中将 kwargs 设置为 CBV 的参数

使用map函数split函数一行键入多个元素

使用map函数split函数一行键入多个元素

RHSA-2018:0395-重要: 内核 安全和BUG修复更新(需要重启本地提权代码执行)

5JUC--实现 Callable 接口