Python元类使用__setattr__修改类属性报dictproxy赋值错误原因求解
错误原因解析
- 不管是Python 2还是Python 3,类对象的
__dict__都是只读的代理对象(Python 2中叫dictproxy,Python 3中叫mappingproxy),设计上就不允许直接对该字典做项赋值操作,你在元类__setattr__中执行self.__dict__['_shelve'] = xxx、self.__dict__[name] = value的操作,直接触发了该代理对象的写入限制,所以抛出报错。 - 此外还有一个隐含逻辑问题:你把
foo、bar、_shelve这几个初始属性写在了元类的定义中,这些属性会变成元类本身的属性,而非你创建的DATA类的属性,后续访问DATA.foo实际是在查找元类的属性,不符合你的设计预期。
修正后可用的实现方案
Python 2 版本
import shelve class _DATA_MetaClass(type): def __init__(cls, name, bases, attrs): # 初始属性直接绑定到目标类 cls.foo = {} cls.bar = {} cls._shelve = None def __setattr__(cls, name, value): if cls._shelve is None: # 调用父类type的原生__setattr__修改类属性,避免直接操作只读的dictproxy super(_DATA_MetaClass, cls).__setattr__('_shelve', shelve.open('datastorage.shelve')) # 写入shelve完成持久化 cls._shelve[name] = value # 修改类属性 super(_DATA_MetaClass, cls).__setattr__(name, value) class DATA(object): __metaclass__ = _DATA_MetaClass # 测试 DATA.x = 'val' print(DATA.x) print(DATA._shelve['x'])
Python 3 版本
import shelve class _DATA_MetaClass(type): def __init__(cls, name, bases, attrs): cls.foo = {} cls.bar = {} cls._shelve = None def __setattr__(cls, name, value): if cls._shelve is None: super().__setattr__('_shelve', shelve.open('datastorage.shelve')) cls._shelve[name] = value super().__setattr__(name, value) class DATA(metaclass=_DATA_MetaClass): pass # 测试 DATA.x = 'val' print(DATA.x) print(DATA._shelve['x'])
注意:程序退出前请主动调用
DATA._shelve.close()关闭shelve文件,避免数据丢失。
内容的提问来源于stack exchange,提问作者tim
相关产品推荐
相关产品推荐

