Yanıtlar:
İle new_list = my_list
, gerçekte iki listeyi yok. Ödev, referansı gerçek listeye değil, listeye kopyalar, bu nedenle her ikisi de new_list
ve my_list
ödevden sonra aynı listeye bakın.
Listeyi gerçekten kopyalamak için çeşitli olasılıklarınız vardır:
Yerleşik list.copy()
yöntemi kullanabilirsiniz (Python 3.3'ten beri kullanılabilir):
new_list = old_list.copy()
Dilim yapabilirsiniz:
new_list = old_list[:]
Alex Martelli'nin (en azından 2007'de ) bu konudaki düşüncesi , garip bir sözdizimi olması ve bunu hiç kullanmanın mantıklı olmamasıdır . ;) (Ona göre, bir sonraki daha okunabilir).
Yerleşik işlevi kullanabilirsiniz list()
:
new_list = list(old_list)
Jenerik kullanabilirsiniz copy.copy()
:
import copy
new_list = copy.copy(old_list)
Bu, biraz önce daha yavaş list()
çünkü old_list
ilkinin veri tipini bulmak zorunda .
Liste nesneler içeriyorsa ve bunları da kopyalamak istiyorsanız genel copy.deepcopy()
:
import copy
new_list = copy.deepcopy(old_list)
Açıkçası en yavaş ve en çok belleğe ihtiyaç duyan yöntem, ama bazen kaçınılmaz.
Misal:
import copy
class Foo(object):
def __init__(self, val):
self.val = val
def __repr__(self):
return 'Foo({!r})'.format(self.val)
foo = Foo(1)
a = ['foo', foo]
b = a.copy()
c = a[:]
d = list(a)
e = copy.copy(a)
f = copy.deepcopy(a)
# edit orignal list and instance
a.append('baz')
foo.val = 5
print('original: %r\nlist.copy(): %r\nslice: %r\nlist(): %r\ncopy: %r\ndeepcopy: %r'
% (a, b, c, d, e, f))
Sonuç:
original: ['foo', Foo(5), 'baz']
list.copy(): ['foo', Foo(5)]
slice: ['foo', Foo(5)]
list(): ['foo', Foo(5)]
copy: ['foo', Foo(5)]
deepcopy: ['foo', Foo(1)]
Felix zaten mükemmel bir cevap verdi, ancak çeşitli yöntemlerin hız karşılaştırmasını yapacağımı düşündüm:
copy.deepcopy(old_list)
Copy()
sınıfları deepcopy ile kopyalayan saf python yöntemiCopy()
sınıfları kopyalamamak için saf python yöntemi (yalnızca dikte / listeler / tuples)for item in old_list: new_list.append(item)
[i for i in old_list]
(bir liste anlama )copy.copy(old_list)
list(old_list)
new_list = []; new_list.extend(old_list)
old_list[:]
( liste dilimleme )En hızlı liste dilimleme. Ama unutmayın copy.copy()
, list[:]
ve list(list)
aksine copy.deepcopy()
listesindeki herhangi listeleri, sözlükler ve sınıf örneklerini kopyalamazsanız ve piton versiyonu orijinalleri değiştirirseniz, bu nedenle, onlar da tam tersi kopyalanan listede değişecek.
(İşte ilgilenen veya herhangi bir sorun ortaya çıkarmak isteyen komut dosyası :)
from copy import deepcopy
class old_class:
def __init__(self):
self.blah = 'blah'
class new_class(object):
def __init__(self):
self.blah = 'blah'
dignore = {str: None, unicode: None, int: None, type(None): None}
def Copy(obj, use_deepcopy=True):
t = type(obj)
if t in (list, tuple):
if t == tuple:
# Convert to a list if a tuple to
# allow assigning to when copying
is_tuple = True
obj = list(obj)
else:
# Otherwise just do a quick slice copy
obj = obj[:]
is_tuple = False
# Copy each item recursively
for x in xrange(len(obj)):
if type(obj[x]) in dignore:
continue
obj[x] = Copy(obj[x], use_deepcopy)
if is_tuple:
# Convert back into a tuple again
obj = tuple(obj)
elif t == dict:
# Use the fast shallow dict copy() method and copy any
# values which aren't immutable (like lists, dicts etc)
obj = obj.copy()
for k in obj:
if type(obj[k]) in dignore:
continue
obj[k] = Copy(obj[k], use_deepcopy)
elif t in dignore:
# Numeric or string/unicode?
# It's immutable, so ignore it!
pass
elif use_deepcopy:
obj = deepcopy(obj)
return obj
if __name__ == '__main__':
import copy
from time import time
num_times = 100000
L = [None, 'blah', 1, 543.4532,
['foo'], ('bar',), {'blah': 'blah'},
old_class(), new_class()]
t = time()
for i in xrange(num_times):
Copy(L)
print 'Custom Copy:', time()-t
t = time()
for i in xrange(num_times):
Copy(L, use_deepcopy=False)
print 'Custom Copy Only Copying Lists/Tuples/Dicts (no classes):', time()-t
t = time()
for i in xrange(num_times):
copy.copy(L)
print 'copy.copy:', time()-t
t = time()
for i in xrange(num_times):
copy.deepcopy(L)
print 'copy.deepcopy:', time()-t
t = time()
for i in xrange(num_times):
L[:]
print 'list slicing [:]:', time()-t
t = time()
for i in xrange(num_times):
list(L)
print 'list(L):', time()-t
t = time()
for i in xrange(num_times):
[i for i in L]
print 'list expression(L):', time()-t
t = time()
for i in xrange(num_times):
a = []
a.extend(L)
print 'list extend:', time()-t
t = time()
for i in xrange(num_times):
a = []
for y in L:
a.append(y)
print 'list append:', time()-t
t = time()
for i in xrange(num_times):
a = []
a.extend(i for i in L)
print 'generator expression extend:', time()-t
timeit
modülü kullanın . ayrıca, bunun gibi gelişigüzel mikro ölçütlerden çok fazla sonuç çıkaramazsınız.
[*old_list]
kabaca eşdeğer olmalıdır list(old_list)
, ancak genel işlev çağrısı yolları değil sözdizimi olduğundan, çalışma zamanında biraz tasarruf sağlar (ve aksine old_list[:]
dönüştürme yazmaz, [*old_list]
herhangi bir yinelenebilir üzerinde çalışır ve a list
) üretir .
timeit
100k yerine 50m çalışır) bkz. Stackoverflow.com/a/43220129/3745896
[*old_list]
aslında hemen hemen tüm diğer yöntemlerden daha iyi performans gösteriyor. (cevabımı önceki yorumlarda bulabilirsiniz)
Bana Python 3.3+ ' un dilimleme kadar hızlı olması gereken bir yöntem eklediği söylendi :list.copy()
newlist = old_list.copy()
s.copy()
sığ bir kopya oluşturur . s
s[:]
python3.8
, .copy()
olduğu biraz daha hızlı dilimleme daha. Aşağıya bakınız @AaronsHall cevap.
Python'da bir listeyi klonlama veya kopyalama seçenekleri nelerdir?
Python 3'te aşağıdakilerle sığ bir kopya yapılabilir:
a_copy = a_list.copy()
Python 2 ve 3'te, orijinalin tam bir dilimi ile sığ bir kopya elde edebilirsiniz:
a_copy = a_list[:]
Bir listeyi kopyalamanın iki anlamsal yolu vardır. Sığ bir kopya aynı nesnelerin yeni bir listesini, derin bir kopya ise yeni eşdeğer nesneleri içeren yeni bir liste oluşturur.
Sığ bir kopya, yalnızca listedeki nesnelere başvuruların bulunduğu bir kap olan listenin kendisini kopyalar. İçerisindeki nesneler değiştirilebilir ve biri değiştirilirse, değişiklik her iki listeye de yansıtılır.
Bunu Python 2 ve 3'te yapmanın farklı yolları vardır. Python 2 yolları Python 3'te de çalışır.
Python 2'de, bir listenin sığ bir kopyasını oluşturmanın deyimsel yolu, orijinalin tam bir dilimi ile:
a_copy = a_list[:]
Aynı şeyi listeyi liste yapıcısından geçirerek de yapabilirsiniz,
a_copy = list(a_list)
ancak yapıcıyı kullanmak daha az verimlidir:
>>> timeit
>>> l = range(20)
>>> min(timeit.repeat(lambda: l[:]))
0.30504298210144043
>>> min(timeit.repeat(lambda: list(l)))
0.40698814392089844
Python 3'te listeler list.copy
yöntemi alır:
a_copy = a_list.copy()
Python 3.5'te:
>>> import timeit
>>> l = list(range(20))
>>> min(timeit.repeat(lambda: l[:]))
0.38448613602668047
>>> min(timeit.repeat(lambda: list(l)))
0.6309100328944623
>>> min(timeit.repeat(lambda: l.copy()))
0.38122922903858125
New_list = my_list kullanıldığında listem her değiştiğinde new_list değiştirilir. Bu neden?
my_list
yalnızca bellekteki gerçek listeye işaret eden bir addır. Bir new_list = my_list
kopya yapmadığınızı söylediğinizde , yalnızca bellekteki orijinal listeye işaret eden başka bir ad eklersiniz. Listelerin kopyalarını çıkarırken benzer sorunlar yaşayabiliriz.
>>> l = [[], [], []]
>>> l_copy = l[:]
>>> l_copy
[[], [], []]
>>> l_copy[0].append('foo')
>>> l_copy
[['foo'], [], []]
>>> l
[['foo'], [], []]
Liste, içeriğe yalnızca bir işaretçi dizisidir, bu nedenle sığ bir kopya yalnızca işaretçileri kopyalar ve böylece iki farklı listeniz vardır, ancak aynı içeriğe sahiptirler. İçeriğin kopyalarını oluşturmak için derin bir kopyaya ihtiyacınız vardır.
Bir yapmak için Python 2 veya 3'te bir listenin derin kopyasını kullanmak deepcopy
içinde copy
modül :
import copy
a_deep_copy = copy.deepcopy(a_list)
Bunun yeni alt listeler yapmamızı nasıl sağladığını göstermek için:
>>> import copy
>>> l
[['foo'], [], []]
>>> l_deep_copy = copy.deepcopy(l)
>>> l_deep_copy[0].pop()
'foo'
>>> l_deep_copy
[[], [], []]
>>> l
[['foo'], [], []]
Ve böylece derin kopyalanan listenin orijinalinden tamamen farklı bir liste olduğunu görüyoruz. Kendi işlevini yerine getirebilirsin - ama yapma. Standart kitaplığın derin kopya işlevini kullanarak, aksi takdirde sahip olmayacağınız hatalar oluşturabilirsiniz.
eval
Bunun derin kopyalamanın bir yolu olarak kullanıldığını görebilirsiniz, ancak yapmayın:
problematic_deep_copy = eval(repr(a_list))
64 bit Python 2.7'de:
>>> import timeit
>>> import copy
>>> l = range(10)
>>> min(timeit.repeat(lambda: copy.deepcopy(l)))
27.55826997756958
>>> min(timeit.repeat(lambda: eval(repr(l))))
29.04534101486206
64 bit Python 3.5 üzerinde:
>>> import timeit
>>> import copy
>>> l = list(range(10))
>>> min(timeit.repeat(lambda: copy.deepcopy(l)))
16.84255409205798
>>> min(timeit.repeat(lambda: eval(repr(l))))
34.813894678023644
list_copy=[]
for item in list: list_copy.append(copy(item))
ve çok daha hızlı.
Size uygun bir kopyayı nasıl oluşturacağınızı söyleyen birçok cevap var, ancak hiçbiri orijinal 'kopyanızın' neden başarısız olduğunu söylemiyor.
Python değerleri değişkenlerde saklamaz; isimleri nesnelere bağlar. Orijinal ödeviniz, atıfta bulunulan nesneyi aldı my_list
ve ona da bağladı new_list
. Hangi adı kullanırsanız kullanın, hala yalnızca bir liste vardır, bu nedenle söz konusu şekilde adlandırılırken yapılan değişiklikler, söz konusu my_list
ifadeye atıfta bulunulurken devam edecektir new_list
. Bu soruya verilen diğer yanıtların her biri, bağlanacak yeni bir nesne oluşturmanın farklı yollarını sunar new_list
.
Listenin her öğesi bir ad gibi davranır, çünkü her öğenin yalnızca bir nesneye bağlanmaz. Sığ bir kopya, öğeleri daha önce olduğu gibi aynı nesnelere bağlanan yeni bir liste oluşturur.
new_list = list(my_list) # or my_list[:], but I prefer this syntax
# is simply a shorter way of:
new_list = [element for element in my_list]
Listenizi bir adım daha ileri götürmek için, listenizin referans aldığı her nesneyi kopyalayın ve bu öğe kopyalarını yeni bir listeye bağlayın.
import copy
# each element must have __copy__ defined for this...
new_list = [copy.copy(element) for element in my_list]
Bu henüz derin bir kopya değildir, çünkü listenin her öğesi tıpkı liste öğelerine bağlı olduğu gibi diğer nesnelere başvurabilir. Listedeki her öğeyi özyineli olarak ve sonra her öğenin başvurduğu diğer nesneleri kopyalamak ve bu şekilde devam etmek için: derin bir kopya gerçekleştirin.
import copy
# each element must have __deepcopy__ defined for this...
new_list = copy.deepcopy(my_list)
Kopyalamadaki köşe kutuları hakkında daha fazla bilgi için belgelere bakın .
kullanım thing[:]
>>> a = [1,2]
>>> b = a[:]
>>> a += [3]
>>> a
[1, 2, 3]
>>> b
[1, 2]
>>>
En baştan başlayalım ve bu soruyu inceleyelim.
Diyelim ki iki listeniz var:
list_1=['01','98']
list_2=[['01','98']]
Ve şimdi ilk listeden başlayarak her iki listeyi de kopyalamamız gerekiyor:
İlk önce değişkeni copy
orijinal listemize ayarlayarak deneyelim list_1
:
copy=list_1
Şimdi kopyaların list_1 kopyalandığını düşünüyorsanız, yanılıyorsunuz. id
İki değişken aynı nesneye işaret eğer fonksiyon bize gösterebilir. Hadi bunu deneyelim:
print(id(copy))
print(id(list_1))
Çıktı:
4329485320
4329485320
Her iki değişken de aynı argümandır. Şaşırdın mı?
Python'un bir değişkende hiçbir şey saklamadığını bildiğimizden, Değişkenler sadece nesneye başvuruyor ve nesne değeri saklıyor. Burada nesne bir list
ama aynı nesneye iki farklı değişken adıyla iki referans oluşturduk. Bu, her iki değişkenin de yalnızca farklı adlarla aynı nesneyi işaret ettiği anlamına gelir.
Bunu yaptığınızda copy=list_1
, aslında:
Burada resim listesi_1 ve kopyada iki değişken adı vardır, ancak nesne her iki değişken için de aynıdır. list
Dolayısıyla, kopyalanan listeyi değiştirmeye çalışırsanız, liste yalnızca bir liste olduğu için orijinal listeyi de değiştirir, kopyalanan listeden veya orijinal listeden ne yaparsanız yapın bu listeyi değiştireceksiniz:
copy[0]="modify"
print(copy)
print(list_1)
çıktı:
['modify', '98']
['modify', '98']
Böylece orijinal listeyi değiştirdi:
Şimdi listeleri kopyalamak için bir pythonic yöntemine geçelim.
copy_1=list_1[:]
Bu yöntem, sahip olduğumuz ilk sorunu giderir:
print(id(copy_1))
print(id(list_1))
4338792136
4338791432
Yani her iki listemizin de farklı kimliğe sahip olduğunu görebiliyoruz ve her iki değişkenin de farklı nesnelere işaret ettiği anlamına geliyor. Aslında burada olan şey:
Şimdi listeyi değiştirmeye çalışalım ve hala bir önceki sorunla karşı karşıya olup olmadığımızı görelim:
copy_1[0]="modify"
print(list_1)
print(copy_1)
Çıktı:
['01', '98']
['modify', '98']
Gördüğünüz gibi, yalnızca kopyalanan listeyi değiştirdi. Bu işe yaradığı anlamına gelir.
Sence bitti mi? Hayır. Yuvalanmış listemizi kopyalamaya çalışalım.
copy_2=list_2[:]
list_2
kopyası olan başka bir nesneye başvurmalıdır list_2
. Hadi kontrol edelim:
print(id((list_2)),id(copy_2))
Çıktıyı elde ederiz:
4330403592 4330403528
Şimdi her iki listenin farklı bir nesneyi işaret ettiğini varsayabiliriz, şimdi değiştirmeye çalışalım ve görelim ki istediğimizi veriyoruz:
copy_2[0][1]="modify"
print(list_2,copy_2)
Bu bize çıktı verir:
[['01', 'modify']] [['01', 'modify']]
Bu biraz kafa karıştırıcı görünebilir, çünkü daha önce kullandığımız aynı yöntem işe yaradı. Bunu anlamaya çalışalım.
Yaptığınızda:
copy_2=list_2[:]
İç listeyi değil, yalnızca dış listeyi kopyalıyorsunuz. Bunu id
kontrol etmek için işlevi bir kez daha kullanabiliriz.
print(id(copy_2[0]))
print(id(list_2[0]))
Çıktı:
4329485832
4329485832
Yaptığımızda copy_2=list_2[:]
, bu olur:
Listenin kopyasını oluşturur, ancak yalnızca dış liste kopyasını oluşturur, iç içe liste kopyası değil, iç içe liste her iki değişken için de aynıdır, bu nedenle iç içe listeyi değiştirmeye çalışırsanız, iç içe liste nesnesi aynı olduğundan orijinal listeyi de değiştirir her iki liste için.
Çözüm nedir? Çözüm deepcopy
işlevdir.
from copy import deepcopy
deep=deepcopy(list_2)
Şunu kontrol edelim:
print(id((list_2)),id(deep))
4322146056 4322148040
Her iki dış listenin farklı kimlikleri vardır, bunu iç yuvalanmış listelerde deneyelim.
print(id(deep[0]))
print(id(list_2[0]))
Çıktı:
4322145992
4322145800
Gördüğünüz gibi her iki kimlik de farklıdır, yani her iki iç içe listenin şimdi farklı bir nesneyi gösterdiğini varsayabiliriz.
Bu, deep=deepcopy(list_2)
gerçekte ne olduğunu yaptığınızda anlamına gelir :
Her iki iç içe liste farklı nesneyi işaret ediyor ve şimdi iç içe listenin ayrı bir kopyası var.
Şimdi iç içe listeyi değiştirmeye çalışalım ve önceki sorunu çözüp çözmediğini görelim:
deep[0][1]="modify"
print(list_2,deep)
Çıktıları:
[['01', '98']] [['01', 'modify']]
Gördüğünüz gibi, orijinal iç içe listeyi değiştirmedi, sadece kopyalanan listeyi değiştirdi.
İşte Python 3.6.8 kullanarak zamanlama sonuçları. Bu zamanların mutlak değil, birbiriyle göreceli olduğunu unutmayın.
Sadece sığ kopyalar yapmayı bıraktım ve Python2'de mümkün olmayan bazı yeni yöntemler ekledim, örneğin list.copy()
(Python3 dilim eşdeğeri ) ve iki liste açma ( *new_list, = list
ve new_list = [*list]
) biçimi :
METHOD TIME TAKEN
b = [*a] 2.75180600000021
b = a * 1 3.50215399999990
b = a[:] 3.78278899999986 # Python2 winner (see above)
b = a.copy() 4.20556500000020 # Python3 "slice equivalent" (see above)
b = []; b.extend(a) 4.68069800000012
b = a[0:len(a)] 6.84498999999959
*b, = a 7.54031799999984
b = list(a) 7.75815899999997
b = [i for i in a] 18.4886440000000
b = copy.copy(a) 18.8254879999999
b = []
for item in a:
b.append(item) 35.4729199999997
Python2 kazananının hala iyi işlediğini görebiliriz, ancak list.copy()
özellikle ikincisinin üstün okunabilirliği göz önüne alındığında Python3'ü çok fazla etkilemez .
Karanlık at, b = [*a]
ham dilimlemeden ~% 25 daha hızlı ve diğer açma yönteminden ( *b, = a
) iki kat daha hızlı olan açma ve yeniden paketleme yöntemidir ( ).
b = a * 1
ayrıca şaşırtıcı derecede iyi.
Bu yöntemlerin listeler dışında herhangi bir girdi için eşdeğer sonuçlar vermediğini unutmayın . Hepsi dilimlenebilir nesneler için çalışır, birkaç yinelenebilir herhangi bir iş için copy.copy()
çalışır , ancak sadece daha genel Python nesneleri için çalışır.
İlgili taraflar için test kodu ( Buradan şablon ):
import timeit
COUNT = 50000000
print("Array duplicating. Tests run", COUNT, "times")
setup = 'a = [0,1,2,3,4,5,6,7,8,9]; import copy'
print("b = list(a)\t\t", timeit.timeit(stmt='b = list(a)', setup=setup, number=COUNT))
print("b = copy.copy(a)\t", timeit.timeit(stmt='b = copy.copy(a)', setup=setup, number=COUNT))
print("b = a.copy()\t\t", timeit.timeit(stmt='b = a.copy()', setup=setup, number=COUNT))
print("b = a[:]\t\t", timeit.timeit(stmt='b = a[:]', setup=setup, number=COUNT))
print("b = a[0:len(a)]\t\t", timeit.timeit(stmt='b = a[0:len(a)]', setup=setup, number=COUNT))
print("*b, = a\t\t\t", timeit.timeit(stmt='*b, = a', setup=setup, number=COUNT))
print("b = []; b.extend(a)\t", timeit.timeit(stmt='b = []; b.extend(a)', setup=setup, number=COUNT))
print("b = []; for item in a: b.append(item)\t", timeit.timeit(stmt='b = []\nfor item in a: b.append(item)', setup=setup, number=COUNT))
print("b = [i for i in a]\t", timeit.timeit(stmt='b = [i for i in a]', setup=setup, number=COUNT))
print("b = [*a]\t\t", timeit.timeit(stmt='b = [*a]', setup=setup, number=COUNT))
print("b = a * 1\t\t", timeit.timeit(stmt='b = a * 1', setup=setup, number=COUNT))
b=[*a]
- bunu yapmanın en belirgin yolu;).
Diğer katılımcılar Tüm verdi harika ancak yöntemlerden sadece ana kadar bahsedilen, siz (tesviye) liste tek boyuta sahip iş cevapları, copy.deepcopy()
bir listeyi kopyalamak ve iç içe işaret yok / klon için çalışır list
siz hazır olduğunuzda nesneler çok boyutlu, iç içe listelerle (liste listesi) çalışma. İken Felix Kling onun cevabını bu kavrama başvurur biraz daha konuya ve muhtemelen daha hızlı alternatif kanıtlamak olabilir yerleşik ins kullanarak geçici bir çözüm için vardır deepcopy
.
İken new_list = old_list[:]
, copy.copy(old_list)'
ve Py3k için old_list.copy()
tek tesviye listeler için işten onlar işaret dönmek list
içinde yuvalanmış nesneler old_list
ve new_list
ve birine değişiklikler list
nesneler diğer da sürüyor.
Her iki tarafından işaret edildiği gibi Aaron Hall ve PM 2Ring kullanarak
eval()
çok daha yavaş da sadece kötü bir fikir değildircopy.deepcopy()
.Bu, çok boyutlu listeler için tek seçeneğin olduğu anlamına gelir
copy.deepcopy()
. Bununla birlikte, orta boyutlu çok boyutlu bir dizide kullanmaya çalıştığınızda performans güneye doğru gittiği için gerçekten bir seçenek değil.timeit
Biyoinformatik uygulamaları için duyulmamış hatta büyük bir 42x42 dizisi kullanmaya çalıştım ve bir yanıt beklemekten vazgeçtim ve bu yazıda düzenlememi yazmaya başladım.O zaman tek gerçek seçenek birden fazla listeyi başlatmak ve bunlar üzerinde bağımsız olarak çalışmaktır. Birinin başka önerileri varsa, çok boyutlu liste kopyalamanın nasıl ele alınacağı konusunda takdir edilecektir.
Diğerlerinin de belirttiği gibi, modülü kullanarak ve çok boyutlu listeler için önemli performans sorunları vardır .copy
copy.deepcopy
repr()
nesneyi yeniden oluşturmak için yeterli olduğuna dair bir garanti yoktur . Ayrıca, eval()
son çare bir araçtır; bkz Eval gerçekten tehlikeli detaylar için SO emektar Ned Batchelder tarafından. Eğer kullanımını savunan Yani eval()
sen gerçekten tehlikeli olabilir bahsetmeliyiz.
eval()
genel olarak Python'da işleve sahip olmanın bir risk olduğudur. Koddaki işlevi kullanıp kullanmamanız o kadar da değil, Python'da kendi başına bir güvenlik deliği. Benim örnek girdi alır bir işlevle onu kullanmıyor input()
, sys.agrv
hatta bir metin dosyası. Daha çok, boş bir çok boyutlu listeyi bir kez başlatma ve daha sonra döngünün her yinelemesinde yeniden başlatma yerine bir döngüde kopyalama yoluna sahip olma çizgisi boyunca ilerler.
new_list = eval(repr(old_list))
, bu yüzden kötü bir fikir olmasının yanı sıra, muhtemelen çalışmak için çok yavaş.
Bu konuya henüz değinilmediğim beni şaşırtıyor, bu yüzden bütünlük uğruna ...
Listenin *
öğelerini de kopyalayacak olan "uyarıcı işleci": ile liste paketini açabilirsiniz .
old_list = [1, 2, 3]
new_list = [*old_list]
new_list.append(4)
old_list == [1, 2, 3]
new_list == [1, 2, 3, 4]
Bu yöntemin bariz dezavantajı, sadece Python 3.5+ 'da mevcut olmasıdır.
Zamanlama akıllıca olsa da, bu diğer yaygın yöntemlerden daha iyi performans gösterir.
x = [random.random() for _ in range(1000)]
%timeit a = list(x)
%timeit a = x.copy()
%timeit a = x[:]
%timeit a = [*x]
#: 2.47 µs ± 38.1 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
#: 2.47 µs ± 54.6 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
#: 2.39 µs ± 58.2 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
#: 2.22 µs ± 43.2 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
old_list
ve new_list
iki farklı listede, bir tanesini düzenlemek diğerini değiştirmeyecektir (öğeleri kendileri doğrudan değiştirmediğiniz sürece (liste listesi gibi), bu yöntemlerin hiçbiri derin kopya değildir).
Python sürümünden bağımsız çok basit bir yaklaşım, çoğu zaman kullanabileceğiniz verilen cevaplarda eksikti (en azından ben):
new_list = my_list * 1 #Solution 1 when you are not using nested lists
Ancak, listem başka kapsayıcılar içeriyorsa (örneğin, iç içe listeler için) yukarıdaki kopyalarda yukarıda verilen yanıtlarda önerildiği gibi derin kopya kullanmalısınız. Örneğin:
import copy
new_list = copy.deepcopy(my_list) #Solution 2 when you are using nested lists
. Bonus : Öğeleri kopyalamak istemiyorsanız kullanın (sığ kopya olarak da bilinir):
new_list = my_list[:]
Çözüm # 1 ve Çözüm # 2 arasındaki farkı anlayalım
>>> a = range(5)
>>> b = a*1
>>> a,b
([0, 1, 2, 3, 4], [0, 1, 2, 3, 4])
>>> a[2] = 55
>>> a,b
([0, 1, 55, 3, 4], [0, 1, 2, 3, 4])
Gördüğünüz gibi, # 1 numaralı çözüm yuvalanmış listeleri kullanmadığımızda mükemmel bir şekilde çalıştı. Yuvalanmış listelere 1 numaralı çözümü uyguladığımızda ne olacağını kontrol edelim.
>>> from copy import deepcopy
>>> a = [range(i,i+4) for i in range(3)]
>>> a
[[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]]
>>> b = a*1
>>> c = deepcopy(a)
>>> for i in (a, b, c): print i
[[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]]
[[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]]
[[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]]
>>> a[2].append('99')
>>> for i in (a, b, c): print i
[[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5, 99]]
[[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5, 99]] #Solution#1 didn't work in nested list
[[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]] #Solution #2 - DeepCopy worked in nested list
Kendi özel sınıfınızı tanımladıysanız ve öznitelikleri korumak istiyorsanız , örneğin Python 3'te alternatifler yerine copy.copy()
veya copy.deepcopy()
yerine kullanmanız gereken bazı durumlar olduğunu unutmayın :
import copy
class MyList(list):
pass
lst = MyList([1,2,3])
lst.name = 'custom list'
d = {
'original': lst,
'slicecopy' : lst[:],
'lstcopy' : lst.copy(),
'copycopy': copy.copy(lst),
'deepcopy': copy.deepcopy(lst)
}
for k,v in d.items():
print('lst: {}'.format(k), end=', ')
try:
name = v.name
except AttributeError:
name = 'NA'
print('name: {}'.format(name))
Çıktılar:
lst: original, name: custom list
lst: slicecopy, name: NA
lst: lstcopy, name: NA
lst: copycopy, name: custom list
lst: deepcopy, name: custom list
new_list = my_list[:]
new_list = my_list
Bunu anlamaya çalışın. Diyelim ki benim_listem X yerindeki yığın bellekte, yani benim_listim X'i gösteriyor. Şimdi atayarak new_list = my_list
yeni_listenin X'i işaret etmesine izin verelim. Bu sığ Kopya olarak bilinir.
Şimdi new_list = my_list[:]
atadığımda, sadece my_list öğesinin her nesnesini new_list'e kopyalıyorsunuz demektir. Bu Derin kopya olarak bilinir.
Bunu yapmanın diğer yolu:
new_list = list(old_list)
import copy
new_list = copy.deepcopy(old_list)
Diğer cevaplardan biraz farklı bir şey yayınlamak istedim. Bu muhtemelen en anlaşılır veya en hızlı seçenek olmasa da, derin kopyanın nasıl çalıştığına dair bir iç görünüm ve aynı zamanda derin kopyalama için başka bir alternatif seçenek sunar. İşlevimde hatalar olması gerçekten önemli değil, çünkü bunun amacı soru cevapları gibi nesneleri kopyalamanın bir yolunu göstermek, aynı zamanda bunu, derin kopyanın özünde nasıl çalıştığını açıklamak için bir nokta olarak kullanmaktır.
Herhangi bir derin kopya fonksiyonunun özünde sığ bir kopya yapmanın yolu vardır. Nasıl? Basit. Herhangi bir derin kopyalama işlevi yalnızca değiştirilemeyen nesnelerin kaplarını çoğaltır. Yuvalanmış bir listeyi derin kopyaladığınızda, listelerin içindeki değiştirilebilir nesneleri değil, yalnızca dış listeleri çoğaltırsınız. Yalnızca kapları çoğaltırsınız. Aynı şey sınıflar için de geçerlidir. Bir sınıfı derin kopyaladığınızda, değişebilir niteliklerinin tümünü kopyalarsınız. Nasıl? Neden sadece listeleri, dikte, tuples, iters, sınıflar ve sınıf örnekleri gibi kapsayıcıları kopyalamanız gerekiyor?
Basit. Değişken bir nesne gerçekten çoğaltılamaz. Asla değiştirilemez, bu yüzden sadece tek bir değerdir. Bu, dizeleri, sayıları, boolleri veya bunların herhangi birini asla kopyalamanız gerekmediği anlamına gelir. Ancak kapları nasıl çoğaltırsınız? Basit. Tüm değerleri içeren yeni bir kapsayıcı başlatmanız yeterli. Deepcopy özyinelemeye dayanır. Hiçbir kap kalmayıncaya kadar tüm kapları, içinde kapları olanları bile çoğaltır. Bir kap değişmez bir nesnedir.
Bunu öğrendikten sonra, herhangi bir referans olmadan bir nesneyi tamamen çoğaltmak oldukça kolaydır. Temel veri türlerini derinlemesine kopyalamak için bir işlev (özel sınıflar için işe yaramaz, ancak bunu her zaman ekleyebilirsiniz)
def deepcopy(x):
immutables = (str, int, bool, float)
mutables = (list, dict, tuple)
if isinstance(x, immutables):
return x
elif isinstance(x, mutables):
if isinstance(x, tuple):
return tuple(deepcopy(list(x)))
elif isinstance(x, list):
return [deepcopy(y) for y in x]
elif isinstance(x, dict):
values = [deepcopy(y) for y in list(x.values())]
keys = list(x.keys())
return dict(zip(keys, values))
Python'un kendi yerleşik derin kopyası bu örneğe dayanmaktadır. Tek fark, diğer türleri desteklemesi ve öznitelikleri yeni bir yinelenen sınıfa çoğaltarak kullanıcı sınıflarını desteklemesi ve ayrıca bir not listesi veya sözlük kullanarak zaten görüldüğü bir nesneye referansla sonsuz özyinelemeyi engellemesidir. Ve derin kopyalar elde etmek için gerçekten bu kadar. Özünde derin bir kopya yapmak sadece sığ kopyalar yapmaktır. Umarım bu cevap soruya bir şey katar.
ÖRNEKLER
Bu listeye sahip olduğunuzu varsayalım: [1, 2, 3] . Değişmez sayılar çoğaltılamaz, ancak diğer katman olabilir. Bir liste kavrayışı kullanarak çoğaltabilirsiniz: [1, 2, 3] içindeki x için x
Şimdi, bu listeye sahip olduğunuzu düşünün: [[1, 2], [3, 4], [5, 6]] . Bu kez, listenin tüm katmanlarını derin kopyalamak için özyineleme kullanan bir işlev yapmak istiyorsunuz. Önceki liste kavrayışı yerine:
[x for x in _list]
Listeler için yeni bir tane kullanır:
[deepcopy_list(x) for x in _list]
Ve deepcopy_list şöyle görünür:
def deepcopy_list(x):
if isinstance(x, (str, bool, float, int)):
return x
else:
return [deepcopy_list(y) for y in x]
Sonra artık strs, bools, floast, ints ve hatta listelerin herhangi bir listesini özyineleme kullanarak sonsuz sayıda katmana derinleştirebilen bir işleve sahipsiniz . Ve işte burada, derin kopyalar.
TLDR : Deepcopy nesneleri çoğaltmak için özyineleme kullanır ve yalnızca değiştirilemeyen nesneler çoğaltılamadığından, aynı değişmez nesneleri döndürür. Bununla birlikte, bir nesnenin en dıştaki mutable katmanına ulaşıncaya kadar, değişken nesnelerin en iç katmanlarını derinleştirir.
İd ve gc aracılığıyla belleğe bakmak için pratik bir bakış açısı.
>>> b = a = ['hell', 'word']
>>> c = ['hell', 'word']
>>> id(a), id(b), id(c)
(4424020872, 4424020872, 4423979272)
| |
-----------
>>> id(a[0]), id(b[0]), id(c[0])
(4424018328, 4424018328, 4424018328) # all referring to same 'hell'
| | |
-----------------------
>>> id(a[0][0]), id(b[0][0]), id(c[0][0])
(4422785208, 4422785208, 4422785208) # all referring to same 'h'
| | |
-----------------------
>>> a[0] += 'o'
>>> a,b,c
(['hello', 'word'], ['hello', 'word'], ['hell', 'word']) # b changed too
>>> id(a[0]), id(b[0]), id(c[0])
(4424018384, 4424018384, 4424018328) # augmented assignment changed a[0],b[0]
| |
-----------
>>> b = a = ['hell', 'word']
>>> id(a[0]), id(b[0]), id(c[0])
(4424018328, 4424018328, 4424018328) # the same hell
| | |
-----------------------
>>> import gc
>>> gc.get_referrers(a[0])
[['hell', 'word'], ['hell', 'word']] # one copy belong to a,b, the another for c
>>> gc.get_referrers(('hell'))
[['hell', 'word'], ['hell', 'word'], ('hell', None)] # ('hello', None)
Python'da şunları yaptığınızı unutmayın:
list1 = ['apples','bananas','pineapples']
list2 = list1
Liste2 gerçek listeyi saklamaz, ancak liste1'e bir başvuru yapar. List1'e bir şey yaptığınızda list2 de değişir. listenin orijinal bir kopyasını oluşturmak için kopyalama modülünü kullanın (varsayılan değil, pip'e indirin) ( copy.copy()
basit listeler copy.deepcopy()
için, iç içe olanlar için). Bu, ilk listeyle değişmeyen bir kopya oluşturur.
Deepcopy seçeneği benim için çalışan tek yöntemdir:
from copy import deepcopy
a = [ [ list(range(1, 3)) for i in range(3) ] ]
b = deepcopy(a)
b[0][1]=[3]
print('Deep:')
print(a)
print(b)
print('-----------------------------')
a = [ [ list(range(1, 3)) for i in range(3) ] ]
b = a*1
b[0][1]=[3]
print('*1:')
print(a)
print(b)
print('-----------------------------')
a = [ [ list(range(1, 3)) for i in range(3) ] ]
b = a[:]
b[0][1]=[3]
print('Vector copy:')
print(a)
print(b)
print('-----------------------------')
a = [ [ list(range(1, 3)) for i in range(3) ] ]
b = list(a)
b[0][1]=[3]
print('List copy:')
print(a)
print(b)
print('-----------------------------')
a = [ [ list(range(1, 3)) for i in range(3) ] ]
b = a.copy()
b[0][1]=[3]
print('.copy():')
print(a)
print(b)
print('-----------------------------')
a = [ [ list(range(1, 3)) for i in range(3) ] ]
b = a
b[0][1]=[3]
print('Shallow:')
print(a)
print(b)
print('-----------------------------')
çıktısına yol açar:
Deep:
[[[1, 2], [1, 2], [1, 2]]]
[[[1, 2], [3], [1, 2]]]
-----------------------------
*1:
[[[1, 2], [3], [1, 2]]]
[[[1, 2], [3], [1, 2]]]
-----------------------------
Vector copy:
[[[1, 2], [3], [1, 2]]]
[[[1, 2], [3], [1, 2]]]
-----------------------------
List copy:
[[[1, 2], [3], [1, 2]]]
[[[1, 2], [3], [1, 2]]]
-----------------------------
.copy():
[[[1, 2], [3], [1, 2]]]
[[[1, 2], [3], [1, 2]]]
-----------------------------
Shallow:
[[[1, 2], [3], [1, 2]]]
[[[1, 2], [3], [1, 2]]]
-----------------------------
Çizgi Bunun nedeni, new_list = my_list
değişken için yeni bir başvuru atar my_list
olan new_list
bu benzer C
aşağıdaki kod,
int my_list[] = [1,2,3,4];
int *new_list;
new_list = my_list;
Tarafından yeni bir liste oluşturmak için kopyalama modülünü kullanmalısınız.
import copy
new_list = copy.deepcopy(my_list)
newlist = [*mylist]
Python 3'tenewlist = list(mylist)
de bir ihtimal var .