我dict以一种简单的方式扩展为使用d.key符号而不是直接访问它的值d['key']:
class ddict(dict):
def __getattr__(self, item):
return self[item]
def __setattr__(self, key, value):
self[key] = value
Run Code Online (Sandbox Code Playgroud)
现在,当我尝试腌制它时,它会调用__getattr__find __getstate__,这既不存在也不必要。使用以下方法解压时也会发生同样的情况__setstate__:
>>> import pickle
>>> class ddict(dict):
... def __getattr__(self, item):
... return self[item]
... def __setattr__(self, key, value):
... self[key] = value
...
>>> pickle.dumps(ddict())
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in __getattr__
KeyError: '__getstate__'
Run Code Online (Sandbox Code Playgroud)
我必须如何修改类ddict才能正确选择?
问题不pickle在于您的__getattr__方法通过引发KeyError异常打破了预期的契约。您需要修复您的__getattr__方法以引发AttributeError异常:
def __getattr__(self, item):
try:
return self[item]
except KeyError:
raise AttributeError(item)
Run Code Online (Sandbox Code Playgroud)
现在pickle给出缺少__getstate__自定义钩子的预期信号。
此方法应返回(计算的)属性值或引发
AttributeError异常。
(粗体强调我的)。
如果您坚持保留KeyError,那么至少您需要跳过以双下划线开头和结尾的名称,并AttributeError为这些名称提出一个:
def __getattr__(self, item):
if isinstance(item, str) and item[:2] == item[-2:] == '__':
# skip non-existing dunder method lookups
raise AttributeError(item)
return self[item]
Run Code Online (Sandbox Code Playgroud)
请注意,您可能希望为您的ddict()子类提供一个空__slots__元组;您不需要__dict__实例上的额外属性映射,因为您将属性转移到键值对。这为每个实例节省了大量内存。
演示:
>>> import pickle
>>> class ddict(dict):
... __slots__ = ()
... def __getattr__(self, item):
... try:
... return self[item]
... except KeyError:
... raise AttributeError(item)
... def __setattr__(self, key, value):
... self[key] = value
...
>>> pickle.dumps(ddict())
b'\x80\x03c__main__\nddict\nq\x00)\x81q\x01.'
>>> type(pickle.loads(pickle.dumps(ddict())))
<class '__main__.ddict'>
>>> d = ddict()
>>> d.foo = 'bar'
>>> d.foo
'bar'
>>> pickle.loads(pickle.dumps(d))
{'foo': 'bar'}
Run Code Online (Sandbox Code Playgroud)
这pickle为测试__getstate__方法上的实例,而不是类的是特殊的方法规范,是另一天的讨论。
| 归档时间: |
|
| 查看次数: |
1680 次 |
| 最近记录: |