我要做一个元类,它应该为我的类 CustomClass 的所有属性和方法添加前缀“custom_”,除了魔术方法之外。 这是代码:
class CustomClass(metaclass=CustomMeta):
x = 50
def __init__(self, val=99):
self.val = val
def line(self):
return 100
def __str__(self):
return "Custom_by_metaclass"
我编写了一个适合这种情况的以下元类,但我遇到了一个问题,我无法将实例的参数 self.val 更改为 self.custom_val ,以便我的断言失败:
inst = CustomClass()
assert inst.custom_val == 99 #Fails
无论如何,其他断言没问题:
assert CustomClass.custom_x == 50
inst = CustomClass()
assert inst.custom_x == 50
assert inst.custom_line() == 100
assert str(inst) == "Custom_by_metaclass"
这是我的元类:
class CustomMeta(type):
def __new__(cls, name_class, base, attrs):
custom_attrs = {}
for key, value in attrs.items():
if not key.startswith('__') and not key.endswith('__'):
custom_attrs['custom_' + key] = attrs[key]
else:
custom_attrs[key] = attrs[key]
return type.__new__(cls, name_class, base, custom_attrs)
我应该怎样做才能解决我的问题?
PS。解决方案之一是将 setattr 写入我的 CustomClass
def __setattr__(cls, name, value):
if not (name.startswith('__') and name.endswith('__')):
name = f'custom_{name}'
super().__setattr__(name, value)
它有效,我可以为我的对象动态添加新属性并获取 custom_ 标签。但是有没有办法通过Metaclass来解决呢? 该任务必然要创建和元类,所以我怀疑我的解决方案是否符合要求。
您需要处理在初始化级别创建的 attr
class CustomMeta(type):
def __new__(cls, name_class, base, attrs):
custom_attrs = {}
for key, value in attrs.items():
if not key.startswith('__') and not key.endswith('__'):
custom_attrs['custom_' + key] = attrs[key]
else:
custom_attrs[key] = attrs[key]
# Modify __init__ to set custom attribute names
if '__init__' in attrs:
original_init = attrs['__init__']
def custom_init(self, *args, **kwargs):
original_init(self, *args, **kwargs)
for key, value in vars(self).items():
if not key.startswith('custom_') and not key.startswith('__'):
setattr(self, f'custom_{key}', value)
delattr(self, key)
custom_init.__name__ = '__init__'
custom_attrs['__init__'] = custom_init
return type.__new__(cls, name_class, base, custom_attrs)
class CustomClass(metaclass=CustomMeta):
x = 50
def __init__(self, val=99):
self.val = val
def line(self):
return 100
def __str__(self):
return "Custom_by_metaclass"
assert CustomClass.custom_x == 50
inst = CustomClass()
assert inst.custom_x == 50
assert inst.custom_line() == 100
assert str(inst) == "Custom_by_metaclass"
inst = CustomClass()
assert inst.custom_val == 99 #Fails