Skip to content

gh-152042: Preserve instance __dict__ when copying deque and array subclasses#152043

Open
iamsharduld wants to merge 1 commit into
python:mainfrom
iamsharduld:local-gh-152042-copy-subclass
Open

gh-152042: Preserve instance __dict__ when copying deque and array subclasses#152043
iamsharduld wants to merge 1 commit into
python:mainfrom
iamsharduld:local-gh-152042-copy-subclass

Conversation

@iamsharduld

@iamsharduld iamsharduld commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

copy.copy() of a collections.deque subclass, and both copy.copy() and copy.deepcopy() of an array.array subclass, dropped the instance __dict__. For array the result was also a plain array rather than the subclass. pickle and the list/dict/set subclasses don't have this problem, so the behavior was inconsistent.

>>> import copy
>>> from collections import deque
>>> class D(deque): pass
>>> d = D([1, 2, 3]); d.label = "kept"
>>> copy.copy(d).label          # was AttributeError
'kept'
>>> from array import array
>>> class A(array): pass
>>> a = A("i", [1, 2]); a.tag = "kept"
>>> copy.copy(a).tag, type(copy.copy(a)) is A   # was AttributeError, base array
('kept', True)

deque.__copy__ (shared with deque.copy()) now copies the instance __dict__ onto the new object. array.__copy__/__deepcopy__ now build the actual subclass and copy the __dict__ — shallow for __copy__, deep (via the memo) for __deepcopy__, registering the new object in the memo first so self-referential attributes don't recurse forever.

Both types' __reduce_ex__ already carried this state, which is why pickle (and deepcopy of a deque, which has no __deepcopy__) were already correct.

Fixes #152042.

Comment thread Modules/arraymodule.c
/*[clinic end generated code: output=703b4c412feaaf31 input=2405ecb4933748c4]*/
{
return array_array___copy___impl(self);
PyObject *memo = unused; /* the copy.deepcopy() memo dict */

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the unused argument is now used, why not just call it memo?

Comment thread Modules/arraymodule.c
Py_DECREF(copy);
return NULL;
}
int err = PyDict_SetItem(memo, key, copy);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

memo should be treated as an opaque object here (https://docs.python.org/3/library/copy.html#object.__deepcopy__). We should not set the key I think.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

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

2 participants