如何用装饰器对Python实例属性进行类型检查?
Python中用装饰器做实例属性类型检查的可行方案
你的需求完全可行,当前代码的问题出在静态类型检查器(如mypy)无法识别装饰器已经确保了maybe_none不为None,所以会提示返回值类型不兼容。运行时你的代码其实能正常触发检查,但需要调整代码让类型检查器理解装饰器的作用,或者补充类型断言。
方案一:给装饰器添加类型注解,让类型检查器识别其作用
通过typing模块的类型变量和类型转换,告诉类型检查器:被装饰的方法执行时,实例的maybe_none属性已被确保为非None状态。
import functools from typing import Optional, Callable, TypeVar, cast # 定义类型变量,用于泛型装饰器 Self = TypeVar('Self') ReturnT = TypeVar('ReturnT') def guarantee(func: Callable[[Self], ReturnT]) -> Callable[[Self], ReturnT]: @functools.wraps(func) def wrapper(self: Self, *args, **kwargs): if self.maybe_none is None: raise ValueError("maybe_none 不能为 None") # 给属性做类型断言,让类型检查器确认其非None self.maybe_none = cast(str, self.maybe_none) return func(self, *args, **kwargs) return wrapper class MyClass: def __init__(self): self.maybe_none: Optional[str] = None def set(self, value: str): self.maybe_none = value @guarantee def get(self) -> str: return self.maybe_none # 此时类型检查器不会再报错
方案二:在方法内部补充类型断言(更简洁)
如果不想修改装饰器的类型注解,可以在get方法内部添加assert语句,直接告诉类型检查器maybe_none不为None——虽然和装饰器的检查逻辑重复,但能快速解决类型提示问题:
import functools from typing import Optional def guarantee(func): @functools.wraps(func) def wrapper(self, *args, **kwargs): if self.maybe_none is None: raise ValueError return func(self, *args, **kwargs) return wrapper class MyClass: def __init__(self): self.maybe_none: Optional[str] = None def set(self, value: str): self.maybe_none = value @guarantee def get(self) -> str: assert self.maybe_none is not None, "maybe_none 不能为 None" return self.maybe_none
补充说明
- 运行时两种方案都能正常触发
ValueError检查,确保属性非None时才执行方法。 - 方案一更适合需要复用装饰器的场景,能统一管理类型检查逻辑;方案二更适合简单场景,代码改动更小。
内容的提问来源于stack exchange,提问作者Rick
相关产品推荐
相关产品推荐

