Python通用属性创建简化实现遇问题,求解决方案
解决Python自定义@property重复代码的问题
问题背景
作为Python新手,编写类时需要重复编写大量@property相关的getter、setter代码:
@property def example(self): return self._example @example.setter def example(self, example): if # 校验条件: self._example = example
为了减少重复,编写了Util.custom_property工具方法自动生成属性的getter、setter和deleter,但遇到两个问题:
- 实例化
City对象时传入不符合条件的name(如"a")不会触发校验,只有修改属性时才报错 - 希望在目标类内直接调用方法添加属性,但原实现无法直接将属性添加到目标类,类外调用又担心引用问题
问题1:实例化不触发校验的解决办法
原代码中__init__直接给私有属性self._name赋值,没有走setter方法,所以校验逻辑不会执行。解决办法是在__init__中通过公开属性赋值,触发setter的校验:
修改后的City类初始化方法:
def __init__(self, name): self.name = name # 调用公开属性的setter,触发校验
这样实例化时传入非法值(如"a")会直接触发name_conds里的校验逻辑,抛出对应的异常。
问题2:在目标类内便捷添加属性的优化
原Util.custom_property返回getter/setter/deleter列表,需要手动创建property,不够便捷。可以优化工具方法,让它直接给目标类添加属性,或者使用类装饰器简化流程:
方案1:修改Util类,直接给目标类添加属性
修正原方法中deleter的错误(原代码删除的是self._value,应该对应私有属性_{prop}),并让方法接受目标类作为参数:
class Util: @classmethod def add_custom_property(cls, target_class, prop, conds=None, deletable=False): def getter(self): return getattr(self, f'_{prop}') def setter(self, value): if conds is None or conds(value): setattr(self, f'_{prop}', value) else: raise ValueError(f'Invalid value for {prop}') def deleter(self): if deletable: delattr(self, f'_{prop}') # 修正为对应私有属性 else: print(f"This attribute {prop} can't be deleted.") # 直接将property添加到目标类 setattr(target_class, prop, property(getter, setter, deleter))
使用方式:
from utils import Util def name_conds(name): if not isinstance(name, str): raise TypeError("City name must be a string") if not name.strip(): raise ValueError("City name cannot be blank") if not 2 <= len(name) <= 25: raise ValueError("City name length must be between 2 and 25 characters") return True class City: def __init__(self, name): self.name = name # 直接给City类添加自定义属性 Util.add_custom_property(City, "name", name_conds)
方案2:使用类装饰器更优雅地添加属性
如果觉得类外调用不够直观,可以用类装饰器实现,在类定义时直接指定要添加的属性:
def add_custom_property(prop, conds=None, deletable=False): def decorator(cls): def getter(self): return getattr(self, f'_{prop}') def setter(self, value): if conds is None or conds(value): setattr(self, f'_{prop}', value) else: raise ValueError(f'Invalid value for {prop}') def deleter(self): if deletable: delattr(self, f'_{prop}') else: print(f"This attribute {prop} can't be deleted.") setattr(cls, prop, property(getter, setter, deleter)) return cls return decorator
使用方式:
@add_custom_property("name", name_conds) class City: def __init__(self, name): self.name = name
这种方式更符合Python的装饰器语法,代码结构更清晰。
内容的提问来源于stack exchange,提问作者Radagast
相关产品推荐
相关产品推荐

