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/
答案 0 :(得分:1)
UserDict.__copy__
和UserDict.copy()
之间的预期差异通过链接的源代码中的注释来解释。来自UserDict.__copy__
:
# Create a copy and avoid triggering descriptors
该类的开发人员已确保__copy__
不会触发descriptors。因此UserDict.copy()
是DOES触发描述符的补充方法。这是通过创建空字典的副本并将所有元素重新插入该副本来实现的。
请注意,UserDict
类是很早以前引入的before Python 2.2,作为子类化字典的一种方式。当实现要由技能水平无法预测的开发人员子类化的类时,请采取预防措施,以使即使没有正确编写子类,类实例也可以以合理的方式运行。对我来说,将副本创建为空字典并重新插入元素似乎是一种安全的编程。
另一种选择是按照您的建议从.__copy__()
调用.copy()
,然后写入文档中,子类应覆盖.copy()
来触发描述符。但是,有多少子类的开发人员会阅读文档的那部分内容,理解其含义,花时间覆盖该方法,而不会在实现中引入错误?
答案 1 :(得分:0)
有人可能会从UserDict派生一个类,并在每次插入新元素时覆盖update
以执行一些特殊的操作。通过您的替代实现,副本上不会发生什么特别的事情。