Python如何动态实现子类property属性的getter和setter装饰器
问题解答
1. 动态实现property装饰的可行方案
可以在无需额外依赖的前提下实现该需求,你之前的尝试失败核心是两个问题:
- 不能分两次为同一属性设置不完整的
property对象,需要一次性构造同时包含fget、fset的完整property,或拿到已有property调用setter方法生成新对象再赋值 - 尝试2的辅助函数存在未定义变量
sf的语法错误,掩盖了正确的super赋值逻辑
正确实现代码
修改Dec类的__call__方法如下即可:
class Dec: def __init__(self): print('init - dec') def __call__(self, cls): c = type('A_Dec', (cls,), {}) # 初始化逻辑保持不变 setattr(c, '__init__', lambda sub_self, x: super(type(sub_self), sub_self).__init__(x)) # 定义独立的getter逻辑,可自行添加装饰操作 def custom_get(sub_self): # 此处可添加自定义逻辑 return super(type(sub_self), sub_self).x # 定义独立的setter逻辑,可自行添加装饰操作 def custom_set(sub_self, v): # 此处可添加自定义逻辑,比如打印日志、校验参数 print('装饰后的setter被调用') super(type(sub_self), sub_self).x = v # 一次性构造完整的property对象赋值给子类属性 setattr(c, 'x', property(fget=custom_get, fset=custom_set)) return c
测试效果
运行如下测试代码:
dec_A = Dec()(A) dec_a = dec_A('p') print(dec_a.x) dec_a.x = 'new_val' print(dec_a.x)
输出结果为:
init - dec init getter p 装饰后的setter被调用 setter getter new_val
完全符合预期。
2. 零参数super无法使用的原因
零参数形式的super()依赖Python编译类定义时自动注入的__class__单元格变量和方法的第一个实例参数才能正常工作,仅支持在类定义内部的方法中使用。
你当前的getter/setter函数是动态定义在__call__方法的作用域中,不属于类定义阶段的原生方法,没有对应的自动注入变量,因此必须显式传入super所需的两个参数:子类类型、实例对象,也就是super(type(sub_self), sub_self)的写法才能正常工作。
内容的提问来源于stack exchange,提问作者cards
相关产品推荐
相关产品推荐

