variable programming oriented deepcopy deepclone data python oop object copy

programming - python copy variable



¿Cómo puedo crear una copia de un objeto en Python? (2)

¿Cómo puedo crear una copia de un objeto en Python?

Por lo tanto, si cambio los valores de los campos del nuevo objeto, el viejo objeto no se verá afectado por eso.

Te refieres a un objeto mutable entonces.

En Python 3, las listas obtienen un método de copy (en 2, usarías un corte para hacer una copia):

>>> a_list = list(''abc'') >>> a_copy_of_a_list = a_list.copy() >>> a_copy_of_a_list is a_list False >>> a_copy_of_a_list == a_list True

Copias superficiales

Las copias superficiales son solo copias del contenedor más externo.

list.copy es una copia superficial:

>>> list_of_dict_of_set = [{''foo'': set(''abc'')} ... ] >>> list_of_dict_of_set = [{''foo'': set(''abc'')}] >>> lodos_copy = list_of_dict_of_set.copy() >>> lodos_copy[0][''foo''].pop() ''c'' >>> lodos_copy [{''foo'': {''b'', ''a''}}] >>> list_of_dict_of_set [{''foo'': {''b'', ''a''}}]

No obtienes una copia de los objetos interiores. Son el mismo objeto, por lo que cuando están mutados, el cambio aparece en ambos contenedores.

Copias profundas

Las copias profundas son copias recursivas de cada objeto interior.

>>> lodos_deep_copy = copy.deepcopy(list_of_dict_of_set) >>> lodos_deep_copy[0][''foo''].add(''c'') >>> lodos_deep_copy [{''foo'': {''c'', ''b'', ''a''}}] >>> list_of_dict_of_set [{''foo'': {''b'', ''a''}}]

Los cambios no se reflejan en el original, solo en la copia.

Objetos inmutables

Los objetos inmutables generalmente no necesitan ser copiados. De hecho, si lo intentas, Python solo te dará el objeto original:

>>> a_tuple = tuple(''abc'') >>> tuple_copy_attempt = a_tuple.copy() Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: ''tuple'' object has no attribute ''copy''

Las tuplas ni siquiera tienen un método de copia, así que intentémoslo con un corte:

>>> tuple_copy_attempt = a_tuple[:]

Pero vemos que es el mismo objeto:

>>> tuple_copy_attempt is a_tuple True

Del mismo modo para cadenas:

>>> s = ''abc'' >>> s0 = s[:] >>> s == s0 True >>> s is s0 True

y para los sets congelados, a pesar de que tienen un método de copy :

>>> a_frozenset = frozenset(''abc'') >>> frozenset_copy_attempt = a_frozenset.copy() >>> frozenset_copy_attempt is a_frozenset True

Cuándo copiar objetos inmutables

Los objetos inmutables deben copiarse si necesita copiar un objeto interior mutable.

>>> tuple_of_list = [], >>> copy_of_tuple_of_list = tuple_of_list[:] >>> copy_of_tuple_of_list[0].append(''a'') >>> copy_of_tuple_of_list ([''a''],) >>> tuple_of_list ([''a''],) >>> deepcopy_of_tuple_of_list = copy.deepcopy(tuple_of_list) >>> deepcopy_of_tuple_of_list[0].append(''b'') >>> deepcopy_of_tuple_of_list ([''a'', ''b''],) >>> tuple_of_list ([''a''],)

Como podemos ver, cuando el objeto interior de la copia está mutado, el original no cambia.

Objetos personalizados

Los objetos personalizados usualmente almacenan datos en un atributo __dict__ o en __slots__ (una estructura de memoria tipo tupla).

Para hacer un objeto que se puede copiar, defina __copy__ (para copias poco profundas) y / o __deepcopy__ (para copias profundas).

from copy import copy, deepcopy class Copyable: __slots__ = ''a'', ''__dict__'' def __init__(self, a, b): self.a, self.b = a, b def __copy__(self): return type(self)(self.a, self.b) def __deepcopy__(self, memo): # memo is a dict of id''s to copies id_self = id(self) # memoization avoids unnecesary recursion _copy = memo.get(id_self) if _copy is None: _copy = type(self)( deepcopy(self.a, memo), deepcopy(self.b, memo)) memo[id_self] = _copy return _copy

Tenga en cuenta que deepcopy guarda un diccionario de memoial de id(original) (o números de identidad) para las copias. Para disfrutar del buen comportamiento con estructuras de datos recursivas, asegúrese de no haber hecho una copia y, si lo hizo, devuélvala.

Así que hagamos un objeto:

>>> c1 = Copyable(1, [2])

Y copy hace una copia superficial:

>>> c2 = copy(c1) >>> c1 is c2 False >>> c2.b.append(3) >>> c1.b [2, 3]

Y deepcopy ahora hace una copia profunda:

>>> c3 = deepcopy(c1) >>> c3.b.append(4) >>> c1.b [2, 3]

Me gustaría crear una copia de un objeto. Quiero que el nuevo objeto posea todas las propiedades del antiguo objeto (valores de los campos). Pero quiero tener objetos independientes. Por lo tanto, si cambio los valores de los campos del nuevo objeto, el viejo objeto no se verá afectado por eso.


Creo que lo siguiente debería funcionar con muchos bien educados clasificados en Python:

def copy(obj): return type(obj)(obj)

(Por supuesto, no estoy hablando aquí de "copias profundas", que es una historia diferente, y que puede no ser un concepto muy claro: ¿qué tan profundo es lo suficientemente profundo?)

De acuerdo con mis pruebas con Python 3, para objetos inmutables, como tuplas o cadenas, devuelve el mismo objeto (porque no hay necesidad de hacer una copia superficial de un objeto inmutable), pero para listas o diccionarios crea una copia superficial independiente .

Por supuesto, este método solo funciona para las clases cuyos constructores se comportan en consecuencia. Posibles casos de uso: hacer una copia superficial de una clase de contenedor estándar de Python.