copy.copy()/copy.deepcopy() of deque and array subclasses drop instance attributes (array also changes type)
Ninguém assumiu esta issue ainda.
- Linguagem predominante
- Python
- Estrelas
- 77.2k
- Forks
- 36k
- Métricas de merge de PRs
- Métricas de PR pendentes
Descrição
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
Guia de contribuição
Primeiros passos
- Leia a issue inteira e depois o guia de contribuição do projeto.
- Comente na issue dizendo que vai assumir — evita que duas pessoas façam o mesmo trabalho.
- Faça um fork do repositório e trabalhe em uma branch.
- Abra um pull request que referencie o número da issue.
Direção de pesquisa
Leia Modules/_collectionsmodule.c em deque_copy e Modules/arraymodule.c nos métodos de cópia de array; em seguida, use o reproducer para comparar o tipo da subclasse e os atributos da instância com pickle e subclasses de list. Considera-se concluído quando copy.copy() e copy.deepcopy() preservarem a subclasse e os atributos da instância para deque e array, com cobertura de regressão.
Escrita pelo modelo de indexação a partir do texto da issue.
Avaliação
- Stack de tecnologia
- c, python
- Domínio
- backend
- Tipo de issue
- Bug
- Dificuldade
- 3/5
- Tempo estimado
- 1-2 dias
- Status de atividade
- Estagnada
- Clareza
- Claramente especificada
- Facilidade para iniciantes
- 30/100