Python中是否存在类似partialmethod的property自动生成方案?
解决方案
Python的property本质是可构造的描述符对象,不需要依赖装饰器语法才能创建,直接调用property(fget, fset, fdel)就能生成对应属性,完全可以批量生成后绑定到类上,实现和手写装饰器完全一致的效果。
最简实现方案
你可以直接在类定义完成后批量添加属性,只需要注意规避闭包的延迟绑定问题:
class C: def __init__(self): self.kwargs = {'x' : 0, 'y' : 3, 'z' : True} # 建议把双下划线的私有方法改成单下划线,避免类外访问的名称修饰问题 def _get_arg(self, arg_name): assert arg_name in self.kwargs return self.kwargs[arg_name] def _set_arg(self, arg_name, value): assert arg_name in self.kwargs self.kwargs[arg_name] = value def _del_arg(self, arg_name): assert arg_name in self.kwargs del self.kwargs[arg_name] # 批量生成并绑定property for attr_name in ['x', 'y', 'z']: # 通过默认参数绑定当前循环的attr_name,避免闭包延迟绑定坑 def fget(self, name=attr_name): return self._get_arg(name) def fset(self, value, name=attr_name): return self._set_arg(name, value) def fdel(self, name=attr_name): return self._del_arg(name) # 将生成的property设为类属性 setattr(C, attr_name, property(fget, fset, fdel))
测试效果和你手写的完全一致:
c = C() c.x = 'foo' # 触发setter print(c.x) # 触发getter,输出foo del c.x # 触发deleter
更整洁的类装饰器封装
如果不想把批量生成逻辑放在类外,可以用类装饰器封装,后续新增属性只需要修改装饰器的参数列表即可:
def add_auto_properties(attr_list): def wrapper(cls): for attr_name in attr_list: def fget(self, name=attr_name): return self._get_arg(name) def fset(self, value, name=attr_name): return self._set_arg(name, value) def fdel(self, name=attr_name): return self._del_arg(name) setattr(cls, attr_name, property(fget, fset, fdel)) return cls return wrapper @add_auto_properties(['x', 'y', 'z']) class C: # 类内部逻辑不需要做任何修改 def __init__(self): self.kwargs = {'x' : 0, 'y' : 3, 'z' : True} def _get_arg(self, arg_name): assert arg_name in self.kwargs return self.kwargs[arg_name] def _set_arg(self, arg_name, value): assert arg_name in self.kwargs self.kwargs[arg_name] = value def _del_arg(self, arg_name): assert arg_name in self.kwargs del self.kwargs[arg_name]
注意事项
- 所有循环内定义的get/set/del方法,必须通过默认参数
name=attr_name绑定当前迭代的属性名,否则会因为Python闭包的延迟绑定特性,所有属性最终都会引用循环最后一个属性名,导致逻辑错误。 - 如果你不需要通用的
_get_arg/_set_arg/_del_arg方法,也可以把逻辑直接写到生成的fget/fset/fdel里,省掉三个通用方法的定义,代码会更精简。
内容的提问来源于stack exchange,提问作者Yulia V
相关产品推荐
相关产品推荐

