python-在dotdict上使用copy.deepcopy

python-在dotdict上使用copy.deepcopy,python,python-3.x,copy,deep-copy,Python,Python 3.x,Copy,Deep Copy,我已经在我的应用程序的不同位置使用了dotdict,以增强代码的可读性。我一点也不知道,这会导致很多问题。一个特别恼人的情况是,它似乎与复制库不兼容 这就是我所说的dotdict class DotDict(dict): """dot.notation access to dictionary attributes""" __getattr__ = dict.get __setattr__ = dict.__setitem__ __delattr__ = dict

我已经在我的应用程序的不同位置使用了dotdict,以增强代码的可读性。我一点也不知道,这会导致很多问题。一个特别恼人的情况是,它似乎与复制库不兼容

这就是我所说的dotdict

class DotDict(dict):
    """dot.notation access to dictionary attributes"""
    __getattr__ = dict.get
    __setattr__ = dict.__setitem__
    __delattr__ = dict.__delitem__
i、 e.访问字典属性的方法:
dictionary.attribute

当我尝试

nested_dico = DotDict({'example':{'nested':'dico'}})
copy.deepcopy(nested_dico)
我得到以下错误:

/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/copy.py in deepcopy(x, memo, _nil)
    167                     reductor = getattr(x, "__reduce_ex__", None)
    168                     if reductor:
--> 169                         rv = reductor(4)
    170                     else:
    171                         reductor = getattr(x, "__reduce__", None)

TypeError: 'NoneType' object is not callable
我假设这是因为它不识别我的类DotDict,因此认为它是非类型的


有人知道怎么解决这个问题吗?可能会覆盖副本库的有效类型?

实现自定义数据结构的副本相当容易,smth就是这样

def my_dict_copy(d):
    return {k:v for k,v in d.items()}

d1 = { 'a' :1,'b':2}
d2 = my_dict_copy(d1)
d3 = d1
d1['a'] = 2

print(d1)
print(d2)
print(d3)
输出

{'a': 2, 'b': 2}
{'a': 1, 'b': 2}
{'a': 2, 'b': 2}
您没有提供dict的实现,我假设它响应类方法,如
items()
,如果没有,必须有一种方法可以迭代所有键和值


另外,我假设键和值是不可变的对象,而不是数据结构,否则您还需要复制“k”和“v”(可能使用origin
copy
lib)

查看错误发生的位置,
reducer
不是
None
,但它是一个内置函数,这意味着错误发生在C代码中无法看到回溯的某个地方。但我的猜测是,它试图获得一个不确定是否存在的方法,如果不存在,则准备捕获
AttributeError
。相反,它调用
.get
,它返回
None
,没有错误,因此它尝试调用该方法

此操作正确:

class DotDict(dict):
    """dot.notation access to dictionary attributes"""

    def __getattr__(self, item):
        try:
            return self[item]
        except KeyError as e:
            raise AttributeError from e

    __setattr__ = dict.__setitem__
    __delattr__ = dict.__delitem__

a = DotDict(x=1, b=2)

print(deepcopy(a))
我知道这与您的原始类的行为不同,并且您将无法对可选键使用
,但我认为有必要避免外部代码出现类似错误,因为外部代码期望您的类以可预测的方式运行

编辑:这里有一种实现deepcopy并保留原始
\uuu getattr\uuu
的方法:

class DotDict(dict):
    """dot.notation access to dictionary attributes"""

    __getattr__ = dict.get
    __setattr__ = dict.__setitem__
    __delattr__ = dict.__delitem__

    def __deepcopy__(self, memo=None):
        return DotDict(deepcopy(dict(self), memo=memo))
测试:

dd = DotDict(x=1, b=2, nested=DotDict(y=3))

copied = deepcopy(dd)
print(copied)
assert copied == dd
assert copied.nested == dd.nested
assert copied.nested is not dd.nested
assert type(dd) is type(copied) is type(dd.nested) is type(copied.nested) is DotDict

什么是dotdict?它来自哪里?当访问
\uuuu reduce\uuuu
时,是否可以重写它以抛出AttributeError?请提供并指向您正在使用的特定库。是吗?如果可能的话,最好看看导致错误的代码。实现您自己的副本。。。遍历dict并返回根据注释更新的新oneQuestion。您能举一个例子吗@shahafI需要复制一个嵌套字典,其中有许多不同的层,有各种类型的数据类型(列表、数据帧、字符串、字典…)@Ludo post您的代码需要复制所有数据类型,因此我们可以制定具体的解决方案