首页 > 编程问答 >需要 **kwargs 的 Callable 的类型注释

需要 **kwargs 的 Callable 的类型注释

时间:2024-07-30 13:18:54浏览次数:6  
标签:python python-typing

有一个函数 ( f ) 使用函数签名 ( g ),该函数签名采用已知的第一组参数和任意数量的关键字参数 **kwargs 有没有办法将 **kwargs 包含在 ( f ) 中描述的 ( g ) 的类型签名中?

例如:

from typing import Callable, Any
from functools import wraps
import math


def comparator(f: Callable[[Any, Any], bool]) -> Callable[[str], bool]:
    @wraps(f)
    def wrapper(input_string: str, **kwargs) -> bool:
        a, b, *_ = input_string.split(" ")
        return f(eval(a), eval(b), **kwargs)

    return wrapper


@comparator
def equal(a, b):
    return a == b


@comparator
def equal_within(a, b, rel_tol=1e-09, abs_tol=0.0):
    return math.isclose(a, b, rel_tol=rel_tol, abs_tol=abs_tol)


# All following statements should print `True`
print(equal("1 1") == True)
print(equal("1 2") == False)
print(equal_within("5.0 4.99998", rel_tol=1e-5) == True)
print(equal_within("5.0 4.99998") == False)

函数| || 用 comparator 包装其参数 f ,它将 wrapper 的输入作为字符串使用,解析它并使用 f 对其求值。在这种情况下,Pycharm 会发出警告,指出 f 使用意外参数 return f(eval(a), eval(b), **kwargs) 调用 f ,该参数与预期签名不匹配。 **kwargs Reddit 上的这篇文章

建议添加 Any ... 的类型签名类似 f 前者会导致 TypeError [1],而后者似乎具有误导性,因为

  • f: Callable[[Any, Any, ...], bool]
  • f: Callable[[Any, Any, Any], bool]

至少接受 f 2 个参数,而不是完全接受3. 另一种解决方法是使用 like

打开 Callable args定义,但我想知道是否有更合适的解决方案。 ... like f: Callable[..., bool] , but I'm wondering if there is a more appropriate solution.

  1. TypeError: Callable[[arg, ...], result]: each arg must be a type. Got Ellipsis.

你遇到的问题在于,你试图为一个可以接受任意数量参数的函数定义一个精确的类型签名。虽然 Callable[[Any, Any], bool] 适用于像 equal 这样的简单函数,但它无法处理 equal_within 等函数需要的额外 **kwargs

你已经考虑过使用 Callable[..., bool] ,但正如你所发现的那样,Python 的类型提示还不直接支持这种用法。

那么,你有什么选择呢?

  1. 使用 typing.ParamSpec (Python 3.10+)

ParamSpec 允许你捕获和转发可调用对象的参数。

```python from typing import Callable, ParamSpec, TypeVar, Concatenate

P = ParamSpec("P") R = TypeVar("R")

def comparator(f: Callable[Concatenate[int, int, P], R]) -> Callable[[str, P], R]: @wraps(f) def wrapper(input_string: str, args: P.args, kwargs: P.kwargs) -> R: a, b, _ = input_string.split(" ") return f(int(a), int(b), args, *kwargs) return wrapper

@comparator def equal(a: int, b: int) -> bool: return a == b

@comparator def equal_within(a: int, b: int, rel_tol: float = 1e-09, abs_tol: float = 0.0) -> bool: return math.isclose(a, b, rel_tol=rel_tol, abs_tol=abs_tol) ```

在这个例子中:

  • P = ParamSpec("P") 定义了一个新的参数规范 P
  • Concatenate[int, int, P] 表示函数 f 接受两个 int 参数,后面跟着由 P 捕获的任意参数。
  • wrapper 函数现在使用 *args: P.args **kwargs: P.kwargs 来接受并传递任意数量的参数。

  • 使用 Callable[[Any, ...], bool]

这是最实际的解决方案。虽然它不像 ParamSpec 那样精确,但它能传达函数接受两个或多个参数并返回一个布尔值的信息。

```python from typing import Callable, Any

def comparator(f: Callable[[Any, ...], bool]) -> Callable[[str], bool]: # ... your code ... ```

  1. 忽略类型提示

在某些情况下,如果类型提示带来的复杂性超过了它们提供的价值,你可以选择忽略它们。但这通常不应该是首选的解决方案。

总的来说,对于你的用例,使用 Callable[[Any, ...], bool] 是一种很好的折衷方案,它在可读性和类型安全性之间取得了平衡。如果你的 Python 版本 >= 3.10,并且需要更精确的类型信息传递,那么 ParamSpec 是一个更强大的工具。

标签:python,python-typing
From: 61569324

相关文章

  • 如何将多个变量分配给 python 函数中的单个参数?
    我正在尝试编写一个程序,如果可能的话,它需要一个三项式并对其进行因式分解。每当用户输入A、B和C时,三项式应该通过Factor(product,summation)函数获取,但我似乎无法弄清楚如何将A和C分配给乘积arg,将B分配给我尝试在函数外部声明不同的变量,product=(a*c)和summati......
  • python - 从文本生成音乐
    请给我一些建议为了解释一下,我输入“深度睡眠的睡眠音乐”,它将返回一个wav文件:https://www.youtube.com/watch?v=1wAdQhFJy54或者我给出一个wav文件,它会返回相同的现在这是我尝试过的:https://github.com/facebookresearch/audiocraft......
  • 从零开始的Python开发日记(7):短信验证功能开发流程
    短信验证功能开发流程在开发一个包含登录、注册以及短信验证的功能时,你需要遵循一个系统的开发流程。以下是实现这一功能的基本步骤,包括所需的技术和代码示例。1.环境配置首先,确保你的开发环境已经配置好,并安装了必要的库和工具。pipinstallfastapiuvicornsqlalche......
  • 【Python数值分析】革命:引领【数学建模】新时代的插值与拟合前沿技术
    目录​编辑第一部分:插值的基本原理及应用1.插值的基本原理1.1插值多项式1.2拉格朗日插值 1.3牛顿插值 1.4样条插值2.插值的Python实现2.1使用NumPy进行插值2.2使用SciPy进行插值2.2.1一维插值​编辑2.2.2二维插值3.插值的应用场景3.1数据平......
  • 在家用电脑上设置 Python 和 Jupyter,尝试打开 Jupyter 笔记本并显示错误,无法获取
    我有最新的Python版本3.12.4和以下版本的Jupyter:SelectedJupytercorepackages...IPython:8.26.0ipykernel:6.29.5ipywidgets:notinstalledjupyter_client:8.6.2jupyter_core:5.7.2jupyter_server:2.14.2jupyterlab......
  • Python - Reloading a module
    Eachmoduleisloadedintomemoryonlyonceduringaninterpretersessionorduringaprogramrun,regardlessofthenumberoftimesitisimportedintoaprogram.Ifmultipleimportsoccur,themodule’scodewillnotbeexecutedagainandagain.Suppose......
  • vscode python 3.7 pylance debugpy 插件 vsix
    可能报错  crashed5timesinthelast3minutes.Theserverwillnotberestarted.  ---pylance 可能报错  cannotreadpropertiesofundefinedreadingresolveEnvironment   --- debugger可能      vscodepython3.7调试没有反应......
  • Python获取秒级时间戳与毫秒级时间戳的方法[通俗易懂]
    参考资料:https://cloud.tencent.com/developer/article/21581481、获取秒级时间戳与毫秒级时间戳、微秒级时间戳代码语言:javascript复制importtimeimportdatetimet=time.time()print(t)#原始时间数据print(int(t))......
  • CEFPython
    在Tkinter界面中直接嵌入Selenium的浏览器视图并不是一件直接的事情,因为Selenium本身并不提供图形界面嵌入的功能。Selenium主要用于自动化web浏览器,但它并不直接控制浏览器窗口的显示方式,而是依赖于WebDriver来与浏览器交互。然而,你可以使用一些替代方案来在Tkinter应用中模拟或......
  • 《最新出炉》系列初窥篇-Python+Playwright自动化测试-58 - 文件下载
    1.简介前边几篇文章讲解完如何上传文件,既然有上传,那么就可能会有下载文件。因此宏哥就接着讲解和分享一下:自动化测试下载文件。可能有的小伙伴或者童鞋们会觉得这不是很简单吗,还用你介绍和讲解啊,不说就是访问到下载页面,然后定位到要下载的文件的下载按钮后,点击按钮就可以了。其实......