Why does deepcopy fail with "KeyError: '__deepcopy__'" when copying custom object?
Why does deepcopy fail with "KeyError: '__deepcopy__'" when copying custom object?
我有一个 class 可以将字典转换为这样的对象
class Dict2obj(dict):
__getattr__= dict.__getitem__
def __init__(self, d):
self.update(**dict((k, self.parse(v))
for k, v in d.iteritems()))
@classmethod
def parse(cls, v):
if isinstance(v, dict):
return cls(v)
elif isinstance(v, list):
return [cls.parse(i) for i in v]
else:
return v
当我尝试对对象进行深度复制时出现此错误
import copy
my_object = Dict2obj(json_data)
copy_object = copy.deepcopy(my_object)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/copy.py", line 172, in deepcopy
copier = getattr(x, "__deepcopy__", None)
KeyError: '__deepcopy__'
但是,如果我重写 Dict2obj
class 中的 __getattr__
函数,我就能够进行深层复制操作。请参阅下面的示例
class Dict2obj(dict):
__getattr__= dict.__getitem__
def __init__(self, d):
self.update(**dict((k, self.parse(v))
for k, v in d.iteritems()))
def __getattr__(self, key):
if key in self:
return self[key]
raise AttributeError
@classmethod
def parse(cls, v):
if isinstance(v, dict):
return cls(v)
elif isinstance(v, list):
return [cls.parse(i) for i in v]
else:
return v
为什么我需要重写 __getattr__
方法才能对此 class 返回的对象进行深层复制?
您的第一个 class 会出现此问题,因为 copy.deepcopy
试图调用 getattr(x, "__deepcopy__", None)
。第三个参数的意义在于,如果对象的属性不存在,它returns第三个参数。
这是在the documentation for getattr()
-
中给出的
getattr(object, name[, default])
Return the value of the named attribute of object. name must be a string. If the string is the name of one of the object’s attributes, the result is the value of that attribute. For example, getattr(x, 'foobar') is equivalent to x.foobar. If the named attribute does not exist, default is returned if provided, otherwise AttributeError is raised.
如果底层 __getattr__
引发 AttributeError
并且为 getattr()
函数调用提供了 default
参数,则 AttributeError
被捕获通过 getattr()
函数和它 returns 默认参数,否则它会让 AttributeError
冒泡。例子-
>>> class C:
... def __getattr__(self,k):
... raise AttributeError('asd')
...
>>>
>>> c = C()
>>> getattr(c,'a')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in __getattr__
AttributeError: asd
>>> print(getattr(c,'a',None))
None
但在您的情况下,由于您直接将 dict.__getitem__
分配给 __getattr__
,如果在字典中找不到该名称,则会引发 KeyError
而不是 AttributeError
因此它不会被 getattr()
处理并且你的 copy.deepcopy()
失败。
您应该处理 getattr
中的 KeyError
,然后改为加注 AttributeError
。例子-
class Dict2obj(dict):
def __init__(self, d):
self.update(**dict((k, self.parse(v))
for k, v in d.iteritems()))
def __getattr__(self, name):
try:
return self[name]
except KeyError:
raise AttributeError(name)
...
我有一个 class 可以将字典转换为这样的对象
class Dict2obj(dict):
__getattr__= dict.__getitem__
def __init__(self, d):
self.update(**dict((k, self.parse(v))
for k, v in d.iteritems()))
@classmethod
def parse(cls, v):
if isinstance(v, dict):
return cls(v)
elif isinstance(v, list):
return [cls.parse(i) for i in v]
else:
return v
当我尝试对对象进行深度复制时出现此错误
import copy
my_object = Dict2obj(json_data)
copy_object = copy.deepcopy(my_object)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/copy.py", line 172, in deepcopy
copier = getattr(x, "__deepcopy__", None)
KeyError: '__deepcopy__'
但是,如果我重写 Dict2obj
class 中的 __getattr__
函数,我就能够进行深层复制操作。请参阅下面的示例
class Dict2obj(dict):
__getattr__= dict.__getitem__
def __init__(self, d):
self.update(**dict((k, self.parse(v))
for k, v in d.iteritems()))
def __getattr__(self, key):
if key in self:
return self[key]
raise AttributeError
@classmethod
def parse(cls, v):
if isinstance(v, dict):
return cls(v)
elif isinstance(v, list):
return [cls.parse(i) for i in v]
else:
return v
为什么我需要重写 __getattr__
方法才能对此 class 返回的对象进行深层复制?
您的第一个 class 会出现此问题,因为 copy.deepcopy
试图调用 getattr(x, "__deepcopy__", None)
。第三个参数的意义在于,如果对象的属性不存在,它returns第三个参数。
这是在the documentation for getattr()
-
getattr(object, name[, default])
Return the value of the named attribute of object. name must be a string. If the string is the name of one of the object’s attributes, the result is the value of that attribute. For example, getattr(x, 'foobar') is equivalent to x.foobar. If the named attribute does not exist, default is returned if provided, otherwise AttributeError is raised.
如果底层 __getattr__
引发 AttributeError
并且为 getattr()
函数调用提供了 default
参数,则 AttributeError
被捕获通过 getattr()
函数和它 returns 默认参数,否则它会让 AttributeError
冒泡。例子-
>>> class C:
... def __getattr__(self,k):
... raise AttributeError('asd')
...
>>>
>>> c = C()
>>> getattr(c,'a')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in __getattr__
AttributeError: asd
>>> print(getattr(c,'a',None))
None
但在您的情况下,由于您直接将 dict.__getitem__
分配给 __getattr__
,如果在字典中找不到该名称,则会引发 KeyError
而不是 AttributeError
因此它不会被 getattr()
处理并且你的 copy.deepcopy()
失败。
您应该处理 getattr
中的 KeyError
,然后改为加注 AttributeError
。例子-
class Dict2obj(dict):
def __init__(self, d):
self.update(**dict((k, self.parse(v))
for k, v in d.iteritems()))
def __getattr__(self, name):
try:
return self[name]
except KeyError:
raise AttributeError(name)
...