python / python/cpython

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

Ouverte
#152,042 3 commentaires 0 réactions 0 personnes assignées Voir sur GitHub

Personne n'a encore pris cette issue.

stdlib type-bug
Langage dominant
Python
Étoiles
77.2k
Forks
35.9k
Métriques de merge des PR
Métriques de PR en attente

Description

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

Guide de contribution

Ouvrir le guide de contribution

Par où commencer

  1. Lisez l'issue en entier, puis le guide de contribution du projet.
  2. Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
  3. Forkez le dépôt et travaillez sur une branche.
  4. Ouvrez une pull request qui référence le numéro de l'issue.

Piste de recherche

Lisez Modules/_collectionsmodule.c au niveau de deque_copy et Modules/arraymodule.c au niveau des méthodes de copie de array, puis utilisez le reproducer pour comparer le type de sous-classe et les attributs d’instance avec pickle et les sous-classes de list. C’est terminé lorsque copy.copy() et copy.deepcopy() préservent la sous-classe et les attributs d’instance pour deque et array, avec une couverture de régression.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Évaluation

Stack technique
c, python
Domaine
backend
Type d'issue
Bug
Difficulté
3/5
Temps estimé
1-2 jours
Activité
À l'abandon
Clarté
Clairement spécifiée
Accessibilité débutants
30/100

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.