如何使 类 和 __getattr__ 可选取
how to make classes with __getattr__ pickable
如何修改下面的 类 以使其可挑选?
本题:类似,但在使用getattr时引用了错误的异常。
This other question seems to provide meaningful insight Why does pickle.dumps call __getattr__?, 但是它没有提供一个例子,老实说我不明白我应该实现什么。
import pickle
class Foo(object):
def __init__(self, dct):
for key in dct:
setattr(self, key, dct[key])
class Bar(object):
def __init__(self, dct):
for key in dct:
setattr(self, key, dct[key])
def __getattr__(self, attr):
"""If attr is not in channel, look in timing_data
"""
return getattr(self.foo, attr)
if __name__=='__main__':
dct={'a':1,'b':2,'c':3}
foo=Foo(dct)
dct2={'d':1,'e':2,'f':3,'foo':foo}
bar=Bar(dct2)
pickle.dump(bar,open('test.pkl','w'))
bar=pickle.load(open('test.pkl','r'))
结果:
14 """If attr is not in channel, look in timing_data
15 """
---> 16 return getattr(self.foo, attr)
17
18 if __name__=='__main__':
RuntimeError: maximum recursion depth exceeded while calling a Python object
这里的问题是您的 __getattr__
方法执行不佳。它假定 self.foo
存在。如果 self.foo
不存在,尝试访问它最终会调用 __getattr__
- 这会导致无限递归:
>>> bar = Bar({}) # no `foo` attribute
>>> bar.x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "untitled.py", line 19, in __getattr__
return getattr(self.foo, attr)
File "untitled.py", line 19, in __getattr__
return getattr(self.foo, attr)
File "untitled.py", line 19, in __getattr__
return getattr(self.foo, attr)
[Previous line repeated 329 more times]
RecursionError: maximum recursion depth exceeded while calling a Python object
要解决此问题,如果不存在 foo
属性,则必须抛出 AttributeError:
def __getattr__(self, attr):
"""If attr is not in channel, look in timing_data
"""
if 'foo' not in vars(self):
raise AttributeError
return getattr(self.foo, attr)
(我使用vars
函数获取了对象的字典,因为它看起来比self.__dict__
好看。)
现在一切正常:
dct={'a':1,'b':2,'c':3}
foo=Foo(dct)
dct2={'d':1,'e':2,'f':3,'foo':foo}
bar=Bar(dct2)
data = pickle.dumps(bar)
bar = pickle.loads(data)
print(vars(bar))
# output:
# {'d': 1, 'e': 2, 'f': 3, 'foo': <__main__.Foo object at 0x7f040fc7e7f0>}
如何修改下面的 类 以使其可挑选?
本题:
This other question seems to provide meaningful insight Why does pickle.dumps call __getattr__?, 但是它没有提供一个例子,老实说我不明白我应该实现什么。
import pickle
class Foo(object):
def __init__(self, dct):
for key in dct:
setattr(self, key, dct[key])
class Bar(object):
def __init__(self, dct):
for key in dct:
setattr(self, key, dct[key])
def __getattr__(self, attr):
"""If attr is not in channel, look in timing_data
"""
return getattr(self.foo, attr)
if __name__=='__main__':
dct={'a':1,'b':2,'c':3}
foo=Foo(dct)
dct2={'d':1,'e':2,'f':3,'foo':foo}
bar=Bar(dct2)
pickle.dump(bar,open('test.pkl','w'))
bar=pickle.load(open('test.pkl','r'))
结果:
14 """If attr is not in channel, look in timing_data
15 """
---> 16 return getattr(self.foo, attr)
17
18 if __name__=='__main__':
RuntimeError: maximum recursion depth exceeded while calling a Python object
这里的问题是您的 __getattr__
方法执行不佳。它假定 self.foo
存在。如果 self.foo
不存在,尝试访问它最终会调用 __getattr__
- 这会导致无限递归:
>>> bar = Bar({}) # no `foo` attribute
>>> bar.x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "untitled.py", line 19, in __getattr__
return getattr(self.foo, attr)
File "untitled.py", line 19, in __getattr__
return getattr(self.foo, attr)
File "untitled.py", line 19, in __getattr__
return getattr(self.foo, attr)
[Previous line repeated 329 more times]
RecursionError: maximum recursion depth exceeded while calling a Python object
要解决此问题,如果不存在 foo
属性,则必须抛出 AttributeError:
def __getattr__(self, attr):
"""If attr is not in channel, look in timing_data
"""
if 'foo' not in vars(self):
raise AttributeError
return getattr(self.foo, attr)
(我使用vars
函数获取了对象的字典,因为它看起来比self.__dict__
好看。)
现在一切正常:
dct={'a':1,'b':2,'c':3}
foo=Foo(dct)
dct2={'d':1,'e':2,'f':3,'foo':foo}
bar=Bar(dct2)
data = pickle.dumps(bar)
bar = pickle.loads(data)
print(vars(bar))
# output:
# {'d': 1, 'e': 2, 'f': 3, 'foo': <__main__.Foo object at 0x7f040fc7e7f0>}