python / python/cpython

copy.copy()/copy.deepcopy() of deque and array subclasses drop instance attributes (array also changes type)

Đang mở
#152,042 3 bình luận 0 reaction 0 người được giao Xem trên GitHub

Chưa có ai nhận issue này.

stdlib type-bug
Ngôn ngữ chính
Python
Star
77.2k
Fork
35.9k
Chỉ số merge pull request
Chỉ số pull request đang chờ

Mô tả

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

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Hướng nghiên cứu

Đọc Modules/_collectionsmodule.c tại deque_copy và Modules/arraymodule.c tại các phương thức sao chép của array, sau đó dùng reproducer để so sánh kiểu lớp con và các thuộc tính của instance với pickle và các lớp con của list. Hoàn tất có nghĩa là copy.copy() và copy.deepcopy() giữ nguyên lớp con và các thuộc tính của instance đối với deque và array, kèm theo coverage hồi quy.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Đánh giá

Công nghệ
c, python
Lĩnh vực
backend
Loại issue
Lỗi
Độ khó
3/5
Thời gian dự kiến
1-2 ngày
Mức độ hoạt động
Đình trệ
Độ rõ ràng
Đặc tả rõ ràng
Mức phù hợp với người mới
30/100

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.