如何编写依赖类属性的Python装饰器?或优化同步对象重复代码?
问题描述
我正在编写一个名为Synchronised_object的类,该类接收来自API的外部对象,对其进行处理后暴露实用方法,再将处理后的对象写入数据库。当外部对象不存在时,类方法需要使用数据库记录中的数据。
这导致类方法中出现大量重复的简单代码:
class Synchronised_object: def __init__(self, obj=None, rec=None): self.object = obj self.record = rec def a(self): if self.object: return self.object.a else: return self.record['a'] def b(self): if self.object: return self.object.b.upper() else: return self.record['b']
函数中的重复代码看起来非常适合使用装饰器,但此场景下装饰器代码需依赖实例化类对象的属性,我了解到这存在实现难点。请问是否可以编写依赖self.object的装饰器?如果不行,有没有其他方法减少“if self.object.... else return self.record[name]”这类重复代码?
解决方案
一、可以编写依赖实例属性的装饰器
完全可以实现依赖self.object的装饰器,核心是让装饰器返回的函数能访问到实例本身。这里可以写一个通用装饰器,根据字段名和可选的处理函数封装逻辑:
def sync_field(field_name, processor=None): def decorator(func): def wrapper(self): if self.object: value = getattr(self.object, field_name) return processor(value) if processor else value return self.record[field_name] return wrapper return decorator
在类中使用该装饰器:
class Synchronised_object: def __init__(self, obj=None, rec=None): self.object = obj self.record = rec @sync_field('a') def a(self): pass # 逻辑由装饰器处理,此处无需编写 @sync_field('b', processor=str.upper) def b(self): pass
二、替代方案:使用属性访问器(property)
如果觉得装饰器冗余,直接用Python的property结合内部辅助方法,代码会更紧凑:
class Synchronised_object: def __init__(self, obj=None, rec=None): self.object = obj self.record = rec def _get_sync_value(self, field_name, processor=None): if self.object: value = getattr(self.object, field_name) return processor(value) if processor else value return self.record[field_name] @property def a(self): return self._get_sync_value('a') @property def b(self): return self._get_sync_value('b', processor=str.upper)
三、进阶方案:使用描述符(Descriptor)
如果需要在多个类中复用该同步逻辑,描述符是更优雅的选择:
class SyncFieldDescriptor: def __init__(self, field_name, processor=None): self.field_name = field_name self.processor = processor def __get__(self, instance, owner): if instance.object: value = getattr(instance.object, self.field_name) return self.processor(value) if self.processor else value return instance.record[self.field_name] class Synchronised_object: a = SyncFieldDescriptor('a') b = SyncFieldDescriptor('b', processor=str.upper) def __init__(self, obj=None, rec=None): self.object = obj self.record = rec
这种方式让类的定义极度简洁,所有同步逻辑都由描述符统一处理,适合存在大量同步字段的场景。
内容的提问来源于stack exchange,提问作者weegolo
相关产品推荐
相关产品推荐

