Ik wil graag een kopie van een object maken. Ik wil dat het nieuwe object alle eigenschappen van het oude object (waarden van de velden) bezit. Maar ik wil onafhankelijke objecten hebben. Dus, als ik de waarden van de velden van het nieuwe object wijzig, mag het oude object daar niet door worden beïnvloed.
Antwoord 1, Autoriteit 100%
Om een volledig onafhankelijke kopie van een object te krijgen, kunt u de copy.deepcopy()
functie.
Raadpleeg de andere antwoorden op deze vraag voor meer informatie over ondiep en diepe kopiëren en de leuke uitleg in Dit antwoord op een gerelateerde vraag .
Antwoord 2, Autoriteit 42%
Hoe kan ik een kopie van een object in Python maken?
Dus, als ik waarden van de velden van het nieuwe object wijzig, mag het oude object daar niet door worden beïnvloed.
U bedoelt dan een mutable-object.
In Python 3, lijsten krijgen een copy
methode (in 2, u zou een plak gebruiken om een kopie te maken):
>>> 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
Ondiepe exemplaren
Ondiepe exemplaren zijn alleen kopieën van de buitenste container.
list.copy
is een ondiepe kopie:
>>> 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'}}]
Je krijgt geen kopie van de interieurobjecten. Ze zijn hetzelfde object – dus als ze gemuteerd zijn, verschijnt de wijziging in beide containers.
Diepe kopieën
Diepe kopieën zijn recursieve kopieën van elk interieurobject.
>>> 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'}}]
Wijzigingen worden niet weergegeven in het origineel, alleen in de kopie.
Onveranderlijke objecten
Onveranderlijke objecten hoeven meestal niet te worden gekopieerd. Sterker nog, als je het probeert, zal Python je gewoon het originele object geven:
>>> 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'
Tuples hebben niet eens een kopieermethode, dus laten we het proberen met een plak:
>>> tuple_copy_attempt = a_tuple[:]
Maar we zien dat het hetzelfde object is:
>>> tuple_copy_attempt is a_tuple
True
Hetzelfde geldt voor strings:
>>> s = 'abc'
>>> s0 = s[:]
>>> s == s0
True
>>> s is s0
True
en voor frozensets, ook al hebben ze een copy
methode:
>>> a_frozenset = frozenset('abc')
>>> frozenset_copy_attempt = a_frozenset.copy()
>>> frozenset_copy_attempt is a_frozenset
True
Wanneer u onveranderbare objecten wilt kopiëren
onveranderlijke objecten moeten worden gekopieerd als u een gekopieerd mutaboratoriumobject nodig heeft.
>>> 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'],)
Zoals we kunnen zien, wanneer het interieurobject van de kopie is gemuteerd, doet het origineel niet wijziging.
Aangepaste objecten
Aangepaste objecten slaan gewoonlijk gegevens op in een __dict__
ATTIBUTE of IN __slots__
(een tuple-achtige geheugenstructuur.)
Om een kopieerbaar object te maken, definieert u __copy__
(voor ondiepe exemplaren) en / of __deepcopy__
(voor diepe kopieën).
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
Merk op dat deepcopy
een memoisatiewoordenboek van id(original)
(of identiteitsnummers) bijhoudt aan kopieën. Om te genieten van goed gedrag met recursieve gegevensstructuren, zorg er dan voor dat u nog niet een kopie hebt gedaan en als u dat hebt, retourneert u dat.
Dus laten we een object maken:
>>> c1 = Copyable(1, [2])
en copy
maakt een ondiepe kopie:
>>> c2 = copy(c1)
>>> c1 is c2
False
>>> c2.b.append(3)
>>> c1.b
[2, 3]
en deepcopy
Nu maakt een diepe kopie:
>>> c3 = deepcopy(c1)
>>> c3.b.append(4)
>>> c1.b
[2, 3]
Antwoord 3, Autoriteit 8%
Ondiepe kopie met copy.copy()
#!/usr/bin/env python3
import copy
class C():
def __init__(self):
self.x = [1]
self.y = [2]
# It copies.
c = C()
d = copy.copy(c)
d.x = [3]
assert c.x == [1]
assert d.x == [3]
# It's shallow.
c = C()
d = copy.copy(c)
d.x[0] = 3
assert c.x == [3]
assert d.x == [3]
Diepe kopie met copy.deepcopy()
#!/usr/bin/env python3
import copy
class C():
def __init__(self):
self.x = [1]
self.y = [2]
c = C()
d = copy.deepcopy(c)
d.x[0] = 3
assert c.x == [1]
assert d.x == [3]
Documentatie: https://docs.python.org/3/library/copy. html
Getest op Python 3.6.5.
Antwoord 4
Ik geloof dat het volgende zou moeten werken met veel goed opgevoede klassen in Python:
def copy(obj):
return type(obj)(obj)
(Natuurlijk heb ik het hier niet over “diepe kopieën”, wat een ander verhaal is, en wat misschien niet een heel duidelijk concept is — hoe diep is diep genoeg?)
Volgens mijn tests met Python 3, retourneert het voor onveranderlijke objecten, zoals tuples of strings, hetzelfde object (omdat het niet nodig is om een ondiepe kopie van een onveranderlijk object te maken), maar voor lijsten of woordenboeken creëert het een onafhankelijke ondiepe kopie.
Natuurlijk werkt deze methode alleen voor klassen waarvan de constructeurs zich overeenkomstig gedragen. Mogelijke use-cases: een ondiepe kopie maken van een standaard Python-containerklasse.