如何在Python Typing中仅接受类方法作为关键字参数?
在Python中提取类方法类型用于kwargs类型注解
可以实现类似TypeScript中OnlyMethods的功能,在Python里通过类型系统的映射筛选或动态生成TypedDict来约束关键字参数仅接受目标类的方法名及对应可调用类型。
方案1:动态生成TypedDict(兼容Python 3.8+)
通过代码动态生成仅包含类方法的TypedDict,再用Unpack注解关键字参数:
from typing import TypeVar, Type, Callable, Any, TypedDict, Unpack T = TypeVar('T') def create_method_typed_dict(cls: Type[T]) -> type[TypedDict]: """生成仅包含类公开方法的TypedDict类型""" method_defs = {} for name, attr in cls.__dict__.items(): # 过滤掉魔术方法和非可调用属性 if callable(attr) and not name.startswith('__'): method_defs[name] = Callable[..., Any] return TypedDict(f"OnlyMethods_{cls.__name__}", method_defs) class A: prop: int = 10 def foo(self): pass def bar(self): pass def fun[T](**kwargs: Unpack[create_method_typed_dict(T)]): pass # 合法调用 fun[A](foo=lambda: 123) # 以下调用会被类型检查器(如mypy、pyright)报错 fun[A](prop=200) # 错误:prop不是方法 fun[A](smth=lambda:123) # 错误:smth不是A的方法
方案2:类型层面的映射筛选(Python 3.11+ + pyright支持)
利用typing_extensions的KeyOf实现纯类型层面的筛选,无需动态生成类:
from typing_extensions import TypeVar, KeyOf, Callable, Unpack, TypedDict T = TypeVar('T') # 定义仅保留方法的映射类型,total=False表示允许传部分方法 OnlyMethods = TypedDict( "OnlyMethods", {K: T[K] for K in KeyOf[T] if T[K] extends Callable[..., Any]}, total=False ) def fun[T](**kwargs: Unpack[OnlyMethods[T]]): pass class A: prop: int = 10 def foo(self): pass def bar(self): pass fun[A](foo=lambda: 123) # 合法 fun[A](prop=200) # 类型错误 fun[A](smth=lambda:123) # 类型错误
两种方案都能实现需求:限制fun的关键字参数只能是目标类的公开方法名,且值必须是可调用对象。其中方案2更贴近TypeScript的类型推导方式,依赖pyright等对高级类型语法的支持;方案1兼容性更好,适合低版本Python环境。
内容的提问来源于stack exchange,提问作者Malyutin Egor
相关产品推荐
相关产品推荐

