Yanıtlar:
Bir nesnenin tamamen bağımsız bir kopyasını almak için copy.deepcopy()
işlevi kullanabilirsiniz .
Sığ ve derin kopyalama hakkında daha fazla bilgi için lütfen bu sorunun diğer cevaplarına ve bu sorunun ilgili soruya vereceği güzel açıklamaya bakın .
Python'da bir nesnenin kopyasını nasıl oluşturabilirim?
Bu nedenle, yeni nesnenin alanlarının değerlerini değiştirirsem, eski nesnenin bundan etkilenmemesi gerekir.
Değişebilir bir nesneyi kastediyorsun.
Python 3'te listeler bir copy
yöntem alır (2'de kopya oluşturmak için bir dilim kullanırsınız):
>>> 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
Sığ kopyalar yalnızca en dıştaki kabın kopyalarıdır.
list.copy
sığ bir kopyadır:
>>> 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'}}]
İç nesnelerin bir kopyasını alamazsınız. Bunlar aynı nesnedir - bu yüzden mutasyona uğradığında, değişiklik her iki kapta da görülür.
Derin kopyalar, her bir iç nesnenin özyinelemeli kopyalarıdır.
>>> 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'}}]
Değişiklikler orijinal belgeye değil, yalnızca kopyaya yansıtılır.
Değişmez nesnelerin genellikle kopyalanması gerekmez. Aslında, eğer denerseniz, Python size sadece orijinal nesneyi verecektir:
>>> 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'ın bir kopyalama yöntemi bile yok, bu yüzden bir dilim ile deneyelim:
>>> tuple_copy_attempt = a_tuple[:]
Ama aynı nesne olduğunu görüyoruz:
>>> tuple_copy_attempt is a_tuple
True
Benzer şekilde dizeler için:
>>> s = 'abc'
>>> s0 = s[:]
>>> s == s0
True
>>> s is s0
True
ve frozensets için, bir copy
yöntemi olmasına rağmen :
>>> a_frozenset = frozenset('abc')
>>> frozenset_copy_attempt = a_frozenset.copy()
>>> frozenset_copy_attempt is a_frozenset
True
Değişken olmayan objeler olmalı Kopyalanan bir değişken iç nesne gerekiyorsa kopyalanabilir.
>>> 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'],)
Gördüğümüz gibi, kopyanın iç nesnesi mutasyona uğradığında, orijinal değil değiştirin.
Özel nesneler genellikle verileri bir __dict__
öznitelikte veya__slots__
(grup benzeri bir bellek yapısı) .
Kopyalanabilir bir nesne yapmak için __copy__
(sığ kopyalar için) ve / veya __deepcopy__
(derin kopyalar için ) tanımlayı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
deepcopy
İle ilgili bir not sözlüğü tutarid(original)
(veya kimlik numaralarının) not kopyalara . Özyinelemeli veri yapılarıyla iyi davranışların tadını çıkarmak için, daha önce bir kopya oluşturmadığınızdan ve varsa iade edin.
Öyleyse bir nesne yapalım:
>>> c1 = Copyable(1, [2])
Ve copy
sığ bir kopya yapar:
>>> c2 = copy(c1)
>>> c1 is c2
False
>>> c2.b.append(3)
>>> c1.b
[2, 3]
Ve deepcopy
şimdi derin bir kopya çıkarıyor:
>>> c3 = deepcopy(c1)
>>> c3.b.append(4)
>>> c1.b
[2, 3]
İle sığ kopya 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]
İle derin kopya 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]
Belgeler: https://docs.python.org/3/library/copy.html
Python 3.6.5 üzerinde test edilmiştir.
Aşağıdakilerin Python'da iyi niyetli birçok sınıfla çalışması gerektiğine inanıyorum:
def copy(obj):
return type(obj)(obj)
(Tabii ki, burada farklı bir hikaye olan ve çok açık bir kavram olmayan "derin kopyalar" dan bahsetmiyorum - yeterince derin ne kadar derin?)
Python 3 ile yaptığım testlere göre, tuples veya dizeler gibi değişmez nesneler için aynı nesneyi döndürür (çünkü değişmez bir nesnenin sığ bir kopyasını oluşturmaya gerek yoktur), ancak listeler veya sözlükler için bağımsız bir sığ kopya oluşturur .
Tabii ki bu yöntem sadece yapıcıları buna göre davranan sınıflar için işe yarar. Olası kullanım örnekleri: standart bir Python konteyner sınıfının sığ bir kopyasını oluşturma.
__init__
. Yani, bu yöntemin belirli amaçlar için yeterince iyi olabileceğini düşündüm. Her durumda, bu öneri hakkında bilgilendirici yorumlarla ilgileneceğim.
class Foo(object): def __init__(self, arg): super(Foo, self).__init__() self.arg = arg
Basic'i olduğu gibi düşünün . Ben yoksa foo = Foo(3) bar = copy(foo) print(foo.arg) # 3 print(bar.arg) # <__main__.Foo object at ...>
senin o Anlamı copy
fonksiyon sınıflarının bile en temel için kırılır. Yine, bu temiz bir hile (dolayısıyla DV yok), ama bir cevap değil.
copy.copy
sığ kopyalar yapmak için bir yöntem olduğunu gördüm , ama belki de naif olarak, bana bir "sığ kopya oluşturucu" sağlamak sınıfın sorumluluğu olmalı gibi görünüyor. Böyle bir durumda neden aynı arayüz arayüzünü dict
ve list
yapmıyorsunuz? Eğer sınıfınız nesnelerini kopyalama sorumluluğunu almak istiyorsa, neden bir if isinstance(arg, type(self))
madde eklemeyesiniz __init__
?