copy.copy()/copy.deepcopy() of deque and array subclasses drop instance attributes (array also changes type)
还没有人认领这个 Issue。
- 主要语言
- Python
- 星标
- 77.2k
- 派生
- 35.9k
- PR 合并指标
- PR 指标待抓取
描述
Bug report
copy.copy() of a collections.deque subclass, and both copy.copy() and copy.deepcopy() of an array.array subclass, silently drop the instance __dict__. For array the result is also a plain array rather than the subclass. pickle preserves both, and list/dict/set subclasses behave correctly, so this is an inconsistency.
Reproducer
import copy, pickle
from collections import deque
from array import array
class D(deque): pass
d = D([1, 2, 3]); d.label = "kept"
print("deque copy :", getattr(copy.copy(d), "label", "LOST"))
print("deque deepcopy:", getattr(copy.deepcopy(d), "label", "LOST"))
print("deque pickle :", getattr(pickle.loads(pickle.dumps(d)), "label", "LOST"))
class A(array): pass
a = A("i", [1, 2, 3]); a.tag = "kept"
print("array copy :", type(copy.copy(a)).__name__, getattr(copy.copy(a), "tag", "LOST"))
print("array deepcopy:", type(copy.deepcopy(a)).__name__, getattr(copy.deepcopy(a), "tag", "LOST"))
print("array pickle :", type(pickle.loads(pickle.dumps(a))).__name__, getattr(pickle.loads(pickle.dumps(a)), "tag", "LOST"))
Output:
deque copy : LOST
deque deepcopy: kept
deque pickle : kept
array copy : array LOST
array deepcopy: array LOST
array pickle : A kept
A list subclass (and dict/set) preserves the type and attribute in all three cases, which is the expected behavior:
class L(list): pass
l = L([1, 2, 3]); l.label = "kept"
copy.copy(l).label # 'kept'
type(copy.copy(l)) # <class '__main__.L'>
Expected
copy.copy()/copy.deepcopy() should return an object of the same (sub)class with the instance attributes preserved, matching pickle and the behavior of list/dict/set subclasses.
Cause
deque.__copy__ (deque_copy in Modules/_collectionsmodule.c) and array.__copy__/__deepcopy__ (Modules/arraymodule.c) build the new object without copying the instance __dict__; the array versions also don't construct the actual subclass. Each type's __reduce_ex__ already captures the subclass and the __dict__ (that's why pickle and deepcopy-of-deque work), so the custom __copy__/__deepcopy__ shortcuts are what diverge.
Versions
Reproduces on main (3.16.0a0) and 3.12.7.
Linked PRs
- gh-152043
贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
调研方向
阅读 Modules/_collectionsmodule.c 中的 deque_copy 和 Modules/arraymodule.c 中的 array copy methods,然后使用 reproducer 将子类类型和实例属性与 pickle 和 list 子类进行比较。完成的标准是 copy.copy() 和 copy.deepcopy() 对 deque 和 array 保留子类及实例属性,并包含回归测试覆盖。
由索引模型根据 Issue 内容生成。
评估
- 技术栈
- c, python
- 领域
- backend
- Issue 类型
- 缺陷
- 难度
- 3/5
- 预计耗时
- 1-2 天
- 活跃度
- 停滞
- 描述清晰度
- 描述清楚
- 新手友好度
- 30/100