如何通过元类为类实例的非魔法属性添加custom_前缀?
用元类自动为实例属性添加前缀的解决方案
要解决实例初始化时self.val无法自动转为self.custom_val的问题,我们可以通过元类在创建类时自动注入自定义的__setattr__方法,拦截所有实例属性的赋值操作,为非魔法属性自动添加前缀。无需手动在类中编写__setattr__,完全通过元类实现逻辑注入。
完整代码实现
class CustomMeta(type): def __new__(cls, name, bases, attrs): # 处理类属性与方法:为非魔法成员添加custom_前缀 processed_attrs = {} for attr_name, attr_value in attrs.items(): if not (attr_name.startswith('__') and attr_name.endswith('__')): processed_attr_name = f"custom_{attr_name}" processed_attrs[processed_attr_name] = attr_value else: processed_attrs[attr_name] = attr_value # 定义自定义__setattr__:拦截实例属性赋值,自动加前缀 def custom_setattr(self, attr_name, value): # 跳过魔法属性(如__dict__、__class__等) if not (attr_name.startswith('__') and attr_name.endswith('__')): attr_name = f"custom_{attr_name}" # 调用最底层的object.__setattr__完成赋值,避免递归 object.__setattr__(self, attr_name, value) # 将自定义__setattr__注入到类中 processed_attrs['__setattr__'] = custom_setattr # 创建并返回处理后的类 return super().__new__(cls, name, bases, processed_attrs) # 测试用类 class CustomClass(metaclass=CustomMeta): x = 5 y = 8 def __init__(self, val): self.val = val def line(self): return 100 def __str__(self): return "CustomClass" # 验证功能 inst = CustomClass(99) assert inst.custom_val == 99 # 初始化的self.val自动转为self.custom_val assert inst.custom_x == 5 # 类属性x已转为custom_x assert inst.custom_line() == 100 # 类方法line已转为custom_line print("所有断言通过")
关键逻辑说明
- 元类处理类成员:在
__new__方法中遍历类的所有属性和方法,为非魔法成员(不以__开头和结尾的名称)添加custom_前缀,这部分是你已实现的逻辑。 - 注入自定义
__setattr__:- 这个方法会拦截所有实例属性的赋值操作,判断属性名是否为魔法属性,若非魔法属性则自动添加前缀。
- 调用
object.__setattr__而非super().__setattr__,是为了避免触发父类可能存在的自定义__setattr__,确保赋值操作直接作用于实例的属性字典。
- 自动生效:元类创建
CustomClass时,会自动将自定义__setattr__绑定到类上,因此所有CustomClass的实例在赋值属性时都会自动应用前缀逻辑。
可选扩展:支持属性反向访问
如果需要让用户通过inst.val也能访问到inst.custom_val的值,可以在元类中额外注入__getattr__方法:
def custom_getattr(self, attr_name): if not (attr_name.startswith('__') and attr_name.endswith('__')): try: return object.__getattribute__(self, f"custom_{attr_name}") except AttributeError: raise AttributeError(f"'{type(self).__name__}' object has no attribute '{attr_name}'") raise AttributeError(f"'{type(self).__name__}' object has no attribute '{attr_name}'") # 在processed_attrs中添加__getattr__ processed_attrs['__getattr__'] = custom_getattr
这样用户访问inst.val时,会自动映射到inst.custom_val,进一步提升使用便利性。
内容的提问来源于stack exchange,提问作者jadrezz
相关产品推荐
相关产品推荐

