首页 > 编程问答 >Python 中类型友好的委托

Python 中类型友好的委托

时间:2024-07-28 04:56:36浏览次数:10  
标签:python python-typing

考虑以下代码示例

def sum(a: int, b: int):
  return a + b

def wrap(*args, **kwargs):
  # delegate to sum
  return sum(*args, **kwargs)

该代码运行良好,只是类型提示丢失了。 在Python中使用 *args, **kwargs 来实现​​委托模式是很常见的。如果有一种方法可以在使用它们时保留类型提示,那就太好了,但我不知道是否可能以及如何实现。


当然,在使用 *args **kwargs 进行委托时,可以直接保留类型提示。问题是,这些术语本质上是动态的,并且不知道将传递给被委托函数的确切参数。

让我们探索一些改进类型提示的方法,从最不理想到最理想:

1. Callable 和泛型类型提示

我们可以使用 Callable 来提示 wrap 函数,但这会丢失具体的类型信息:

```python from typing import Callable

def sum(a: int, b: int): return a + b

def wrap(func: Callable[..., int], args, kwargs) -> int: return func( args, **kwargs)

result = wrap(sum, 1, 2) # 类型检查器无法推断出sum的参数 ```

这种方法的主要缺点是,它需要手动提供 Callable[..., int] ,并且类型检查器不会强制执行传递给 wrap 的函数实际上采用与 sum 相同的参数。

2. 使用 ParamSpec 进行更精确的类型提示(Python 3.10+)

typing.ParamSpec typing.Concatenate 提供了一种更精确的方法来传播泛型函数签名:

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

P = ParamSpec('P') R = TypeVar('R')

def sum(a: int, b: int) -> int: return a + b

def wrap(func: Callable[P, R], args: P.args, kwargs: P.kwargs) -> R: return func( args, **kwargs)

result = wrap(sum, 1, 2) # 现在可以正确推断类型了 ```

在此示例中, ParamSpec('P') 会捕获被包装函数的完整参数签名,而 Concatenate 允许在需要时修改参数。此方法为类型检查器提供了更多信息,从而可以验证 wrap 函数是否使用正确的参数调用了被包装的函数。

其他注意事项

  • 清晰度与魔力: 虽然 ParamSpec 提供了类型安全性,但它可能会使代码更难理解,尤其是在处理更复杂的委托场景时。在清晰度和严格的类型检查之间取得平衡至关重要。
  • 运行时行为: 重要的是要记住,这些类型提示主要用于静态分析。它们不会在运行时强制执行类型检查。

通过使用 ParamSpec ,可以实现类型安全的委托,同时保留 *args **kwargs 的灵活性。选择最适合的方法取决于项目的复杂性和希望实现的类型安全级别。

标签:python,python-typing
From: 70329648

相关文章

  • 使用 python 支持构建自定义 vim 二进制文件
    背景Debian11vim软件包不包含python3支持。请参阅标题为“Debian11vim中不支持python-证据”的部分下面我需要vim支持python3YouCompleteMevim插件为了构建一个新的,我将vim9.0tarball下载到v......
  • 如何在Python 3.12+中正确使用泛型来提高代码质量?
    我正在尝试使用泛型来改进FastAPI应用程序中的类型注释。我有一个抽象存储库类,在其中使用泛型:fromabcimportABC,abstractmethodfromtypingimportListclassAbstractRepository[T](ABC):@abstractmethodasyncdefadd_one(self,data:dict)->T:......
  • python中的while循环不退出
    我试图完成第一年的python商业课程作业,但我的while循环无法退出,有人能帮忙吗?commisionTable=[{"admin_fee":100,"comm_rate":0.10},{"admin_fee":125,"comm_rate":0.12},{"admin_fee":150,"comm_rate":......
  • python---json文件写入
    ​ 使用到的知识点:os模块执行linux指令、json.dump()、withopenasf代码实现importsysimportosimportjson #向json文件file中添加内容data,其中data的类型为字典defwrite_json(file,data):    #如果文件存在,则删除    if(os.path.exists(fi......
  • python错题记录:布尔运算与逻辑值检测
    一前言环境:python3.10win10二布尔运算与逻辑值检测1案例案例1如上,在布尔运算时,有些时候代码只会运算前面的一部分,剩下的部分根本不会运算。以前在练习算法代码时,就利用这个规则来减少代码的工作量案例2如上,之前好长一段时间,上面的布尔运算总是让我感到困惑布尔运......
  • python---字典遍历
    1、三种常见的字典遍历实现defget_key_value(dics):  '''遍历所有键值对'''  forkey,valueindics.items():    print(f"{key}:{value}")defget_keys(dics):  '''遍历所有的键'''  forkeyindics......
  • python基本语法三天速成系列day1(看完这篇你就会)
    注释注释是代码非常重要的一部分,它的主要作用有:解释代码目的:注释可以说明代码段或函数的目的和功能,帮助其他开发者快速理解代码的意图。复杂逻辑说明:对于复杂的算法或业务逻辑,通过注释可以解释这些逻辑是如何工作的,降低后续维护的难度。提高可读性:良好的注释可以使代码结......
  • Python学习笔记46:游戏篇之外星人入侵(七)
    前言到目前为止,我们已经完成了游戏窗口的创建,飞船的加载,飞船的移动,发射子弹等功能。很高兴的说一声,基础的游戏功能已经完成一半了,再过几天我们就可以尝试驾驶飞船击毁外星人了。当然,计分,游戏次数,背景音乐,开始启动等按钮的功能需要我们慢慢添加,这些功能不影响游戏的使用,影......
  • Python学习笔记45:游戏篇之外星人入侵(六)
    前言飞船模块的功能基本已经完成。今天继续完成子弹模块的功能。子弹模块子弹和飞船模块,在游戏逻辑中有一种生成与被生成的表面关系,因为子弹在游戏中是由飞船发射的。但是在我们实际抽象的过程中,飞船与子弹并不是is的关系,甚至可以说不是has的关系。因此我们需要将两个对......
  • 三种语言实现二分(C++/Python/Java)
    题目给定一个按照升序排列的长度为......