UserDict 有__copy__ 和.copy() 方法。前者由copy.copy(x) 触发,后者由x.copy() 触发。 在 copy() 中,它首先将 self.data 设置为 {},最后使用 c.update(self) 填写c.data。但是, update() 将触发 __setitem__ ,可能使 c.data 不同于 self.data
from collections import UserDict
class Foo(UserDict):
def __setitem__(self, key, value):
if isinstance(key, int):
self.data[key] = value
a = Foo({1:2})
# we force it to set key of str type
a.data['3'] = 4
# two different ways to copy
from copy import copy
b = copy(a)
c = a.copy()
# this copy(a) works fine, but a.copy() is not what we expected!!!
assert b == a
assert not c == a
为什么会存在这种不一致? 为什么不只是这个:
def copy(self):
if self.__class__ is UserDict:
return UserDict(self.data.copy())
import copy
return copy.copy(self)
我不知道您可以在 Python3 中直接对 dict
进行子类化。
请参阅:How to "perfectly" override a dict?
Advantages of UserDict class in Python .
无论如何,也许没有理由再为 UserDict
烦恼了。
请参阅提到的网站 Trey Hunner
:https://treyhunner.com/2019/04/why-you-shouldnt-inherit-from-list-and-dict-in-python/
最佳答案
UserDict.__copy__
和 UserDict.copy()
之间的预期区别由您链接的源代码中的注释解释。来自 UserDict.__copy__
:
# Create a copy and avoid triggering descriptors
该类的开发人员已确保 __copy__
不会触发 descriptors .所以 UserDict.copy()
是触发描述符的补充方法。这是通过创建空字典的副本并将所有元素重新插入该副本来实现的。
请注意,UserDict
类很早就引入了,before Python 2.2 ,作为子类化字典的一种方式。当您实现一个旨在由技能水平不可预测的开发人员子类化的类时,您会采取预防措施让类实例以合理的方式运行,即使子类编写得不好。将副本创建为空字典并重新插入元素对我来说就像是一种安全编程。
另一种方法可能是按照您的建议从 .copy()
调用 .__copy__()
,并写入子类应覆盖 的文档.copy()
触发描述符。但是,有多少子类开发人员会阅读文档的那部分内容、理解其含义、花时间重写该方法而不在其实现中引入错误?
关于python - 为什么 UserDict 的 __copy__ 和 copy() 的行为不一致,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56621321/