python / python/cpython

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

Abierto
#152,042 3 comentarios 0 reacciones 0 asignados Ver en GitHub

Nadie ha tomado este issue todavía.

stdlib type-bug
Lenguaje dominante
Python
Estrellas
77.2k
Forks
35.9k
Métricas de merge de PR
Métricas de PR pendientes

Descripción

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

Guía de contribución

Abrir la guía de contribución

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Línea de trabajo

Lee Modules/_collectionsmodule.c en deque_copy y Modules/arraymodule.c en los métodos de copia de array; después, usa el reproductor para comparar el tipo de subclase y los atributos de instancia con pickle y las subclases de list. Se considera hecho cuando copy.copy() y copy.deepcopy() conservan la subclase y los atributos de instancia para deque y array, con cobertura de regresión.

Escrito por el modelo de indexación a partir del texto del issue.

Evaluación

Stack tecnológico
c, python
Área
backend
Tipo de issue
Error
Dificultad
3/5
Tiempo estimado
1-2 días
Estado de actividad
Estancado
Claridad
Bien especificado
Aptitud para principiantes
30/100

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.