尝试在 __getattr__ 中返回默认值时,Python pickle 崩溃
我有一个类似字典的类,我用它来存储一些值作为属性。我最近添加了一些逻辑(__getattr__
),如果属性不存在,则返回 None 。当我这样做的时候,这个泡菜就崩溃了,我想知道为什么?
测试代码:
import cPickle
class DictionaryLike(object):
def __init__(self, **kwargs):
self.__dict__.update(kwargs)
def __iter__(self):
return iter(self.__dict__)
def __getitem__(self, key):
if(self.__dict__.has_key(key)):
return self.__dict__[key]
else:
return None
''' This is the culprit...'''
def __getattr__(self, key):
print 'Retreiving Value ' , key
return self.__getitem__(key)
class SomeClass(object):
def __init__(self, kwargs={}):
self.args = DictionaryLike(**kwargs)
someClass = SomeClass()
content = cPickle.dumps(someClass,-1)
print content
结果:
Retreiving Value __getnewargs__
Traceback (most recent call last):
File <<file>> line 29, in <module>
content = cPickle.dumps(someClass,-1)
TypeError: 'NoneType' object is not callable`
我做了什么蠢事吗?我读过一篇文章,如果键不存在,则 deepcopy() 可能要求我抛出异常?如果是这种情况,有什么简单的方法可以实现我想要的而不抛出异常吗?
最终结果是,如果某些调用
someClass.args.i_dont_exist
我希望它返回 None 。
I have a dictionary like class that I use to store some values as attributes. I recently added some logic(__getattr__
) to return None if an attribute doesn't exist. As soon as I did this pickle crashed, and I wanted some insight into why?
Test Code:
import cPickle
class DictionaryLike(object):
def __init__(self, **kwargs):
self.__dict__.update(kwargs)
def __iter__(self):
return iter(self.__dict__)
def __getitem__(self, key):
if(self.__dict__.has_key(key)):
return self.__dict__[key]
else:
return None
''' This is the culprit...'''
def __getattr__(self, key):
print 'Retreiving Value ' , key
return self.__getitem__(key)
class SomeClass(object):
def __init__(self, kwargs={}):
self.args = DictionaryLike(**kwargs)
someClass = SomeClass()
content = cPickle.dumps(someClass,-1)
print content
Result:
Retreiving Value __getnewargs__
Traceback (most recent call last):
File <<file>> line 29, in <module>
content = cPickle.dumps(someClass,-1)
TypeError: 'NoneType' object is not callable`
Did I do something stupid? I had read a post that deepcopy() might require that I throw an exception if a key doesn't exist? If this is the case is there any easy way to achieve what I want without throwing an exception?
End result is that if some calls
someClass.args.i_dont_exist
I want it to return None.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
实现 __getattr__ 有点棘手,因为它是为每个不存在的属性调用的。在您的情况下,
pickle
模块测试您的类的__getnewargs__
特殊方法并接收None
,这显然是不可调用的。您可能需要更改 __getattr__ 来调用魔术名称的基本实现:
我通常会传递所有以下划线开头的名称,以便我可以避开内部符号的魔术。
Implementing
__getattr__
is a bit tricky, since it is called for every non-existing attribute. In your case, thepickle
module tests your class for the__getnewargs__
special method and receivesNone
, which is obviously not callable.You might want to alter
__getattr__
to call the base implementation for magic names:I usually pass through all names starting with an underscore, so that I can sidestep the magic for internal symbols.
当类中不存在属性时,您需要引发 AttributeError:
我将假设此行为是必需的。来自 getattr 的 python 文档,“当属性查找尚未完成时调用在通常的位置找到该属性(即它不是实例属性,也没有在 self 的类树中找到该属性)。此方法应该返回(计算出的)属性值或引发 AttributeError 异常。
除非您引发异常,否则无法告诉 pickle 等它正在查找的属性未找到。例如,在错误消息中,pickle 正在寻找名为 __getnewargs__ 的特殊可调用方法,pickle 期望如果未找到 AttributeError 异常,则返回值是可调用的。
我想您周围的一项潜在工作也许可以尝试将 pickle 正在寻找的所有特殊方法定义为虚拟方法?
You need to raise an
AttributeError
when an attribute is not present in your class:I am going to assume that this behavior is required. From the python documentation for getattr, "Called when an attribute lookup has not found the attribute in the usual places (i.e. it is not an instance attribute nor is it found in the class tree for self). name is the attribute name. This method should return the (computed) attribute value or raise an AttributeError exception."
There is no way to tell pickle etc that the attribute it's looking for is not found unless you raise the exception. For example, in your error message pickle is looking for a special callable method called
__getnewargs__
, pickle expects that if the AttributeError exception is not found the return value is callable.I guess one potential work around you could perhaps try defining all of the special methods pickle is looking for as dummy methods?