Sio*_*lan 8 counter dictionary python-3.x
我正在编写继承自 Python 类的自定义类dict,或者collections.Counter我面临deepcopy. 问题基本上是deepcopy当继承自dict而不是继承时按预期工作Counter。
这是一个例子:
from copy import deepcopy
from collections import Counter
class MyCounter(Counter):
def __init__(self, foo):
self.foo = foo
class MyDict(dict):
def __init__(self, foo):
self.foo = foo
c = MyCounter(0)
assert c.foo == 0 # Success
c1 = deepcopy(c)
assert c1.foo == 0 # Failure
d = MyDict(0)
assert d.foo == 0 # Success
d1 = deepcopy(d)
assert d1.foo == 0 # Success
Run Code Online (Sandbox Code Playgroud)
我有点不明白为什么会发生这种情况,因为该类的源代码Counter似乎没有改变有关深度复制的任何内容(__deepcopy__例如没有自定义方法)。
我知道我可能必须编写一个自定义__deepcopy__方法,但我不清楚如何编写。一般来说,我宁愿不必这样做,因为它非常适合dict.
任何帮助都感激不尽。
deepcopy有几个后备方案,在此处的答案中有所介绍
在这种情况下,您的特定基类Counter专门化 pickle 序列化,这就是deepcopy将要采用的内容(作为第二个选项,因为不__deepcopy__存在专门化)。
如果您在调试器中单步执行代码,您会发现它最终到达 Counter 的__reduce__方法,其中 python 3.9 的实现Counter具有:
def __reduce__(self):
return self.__class__, (dict(self),)
Run Code Online (Sandbox Code Playgroud)
我们可以看到信息丢失的地方,因为Counter这里的实现依赖于除了字典部分本身之外没有任何其他字段存储在该对象中。
您可以重载__reduce__or __reduce_ex__,这将修复 pickling 并且作为奖励还可以修复 deepcopy,或者您可以重载__deepcopy__并为其提供必要的实现。
实现我们自己的深度复制并不复杂,我们可以使代码非常简单:
class MyCounter(Counter):
def __init__(self, foo):
self.foo = foo
def __deepcopy__(self, memo):
copy_instance = MyCounter(deepcopy(self.foo, memo))
for key, val in self.items():
copy_instance[deepcopy(key, memo)] = val # val is just an int
return copy_instance
c = MyCounter(123)
c['deep'] = 1
c['copy'] = 2
c1 = deepcopy(c)
assert c1.foo == c.foo
assert c1['deep'] == c['deep']
assert c1['copy'] == c['copy']
Run Code Online (Sandbox Code Playgroud)
(在大多数情况下,我可能建议不要重载 Counter 或 dict 以便向它们添加更多属性,而是编写一个具有counter或 dict 实例变量的自定义类。)