You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Python泛型为Blinker Signal的kwargs提供类型提示?

解决方案:泛型绑定Sender与Kwargs类型的TypedSignal

要解决blinker Signal的参数类型检查冗余、签名不一致问题,可结合TypedDict、泛型Protocol与Generic实现一套可复用的类型安全信号封装,同时保证send和connect的签名完全绑定。

实现代码

from typing import Generic, TypeVar, TypedDict, Callable, Protocol
from blinker import Signal

# 定义Sender类型变量
T = TypeVar("T")
# 约束Kwargs必须是TypedDict类型
K = TypeVar("K", bound=TypedDict)

# 定义接收器的协议,统一约束sender和kwargs类型
class ReceiverProtocol(Generic[T, K], Protocol):
    def __call__(self, sender: T, **kwargs: K) -> None: ...

# 泛型TypedSignal,继承自blinker.Signal
class TypedSignal(Generic[T, K], Signal):
    def send(self, sender: T, **kwargs: K) -> list[tuple[Callable, None]]:
        return super().send(sender, **kwargs)
    
    def connect(self, receiver: ReceiverProtocol[T, K]) -> Callable:
        return super().connect(receiver)

使用示例

# 定义业务实体
class User:
    pass

# 定义该信号要求的kwargs类型(必须为TypedDict)
class UserUpdateKwargs(TypedDict):
    time: int
    audit: str

# 实例化类型安全的信号
user_update = TypedSignal[User, UserUpdateKwargs]()

# 正确的接收器:参数类型完全匹配
@user_update.connect
def handle_user_update(sender: User, *, time: int, audit: str) -> None:
    print(f"User updated: {sender}, time: {time}, audit: {audit}")

# 正确调用:sender和kwargs类型符合要求
user_update.send(User(), time=1620000000, audit="admin_operation")

# 以下操作会触发mypy类型检查错误
# 错误:缺少audit参数
# user_update.send(User(), time=1620000000)
# 错误:sender类型不匹配
# @user_update.connect
# def bad_receiver(sender: str, time: int, audit: str) -> None: ...

方案优势

  1. 无冗余代码:每个信号仅需定义对应的TypedDict即可,无需重复子类化Signal
  2. 签名强绑定:send和connect共享同一组泛型参数(T为sender类型,K为kwargs类型),避免两者签名不一致导致的运行时错误
  3. 完整类型检查:mypy会严格校验send的kwargs参数、接收器的参数类型与定义的约束完全匹配

对原尝试问题的解释

  1. 仅支持位置参数的ParamSpec方案:未结合TypedDict约束kwargs,无法满足blinker以kwargs传递后续参数的场景
  2. TypeVarTuple方案:mypy对**Unpack[TypeVarTuple]的支持有限,仅允许TypedDict作为**参数的类型来源,因此直接使用TypeVarTuple无法实现kwargs的强类型检查
  3. ParamSpec+Protocol方案:错误地将Protocol直接作为泛型参数传入,正确的做法是定义泛型Protocol,让TypedSignal绑定Protocol的类型参数,而非直接传入Protocol类型

类型系统支持性

当前Python类型系统(配合mypy 1.9.0)完全支持该需求,通过TypedDict+泛型Protocol的组合,可完美实现blinker信号的类型安全封装。

内容的提问来源于stack exchange,提问作者Michoel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 22:30:37