Python’da, bir nesneyi kopyalamak için “=” operatörü kullanılır. Ancak, daha önceki konularda anlattığımız gibi bu referans tipli bir atamadır. Başka bir değişle her iki değişkenin gösterdiği adresler aynıdır. Örneğin, listeye yeni elemanlar eklediğimizde her iki liste etkilenir. Bu bölüm gerçekten bir kopyaya ihtiyacımız olduğunda ne yapmamız gerektiği üzerinedir. Öncelikle geçmişe bir dönüş yapıp, basit bir kodla problemi anlatalım.
1 2 3 4 5 6 7 8 9 10 |
eski_list = [[10, 20.2, 30], [-40, 50, 60], [70, 80, 'Test']] yeni_list = eski_list yeni_list[2][2] = 9.9 #bir değeri update işlemi print('Eski Liste:', eski_list) print('Eski liste ID si:', id(eski_list)) print('Yeni Liste:', yeni_list) print('Yeni Liste ID si:', id(yeni_list)) |
1 2 3 4 |
Eski Liste: [[10, 20.2, 30], [-40, 50, 60], [70, 80, 9.9]] Eski liste ID si: 2585460285512 Yeni Liste: [[10, 20.2, 30], [-40, 50, 60], [70, 80, 9.9]] Yeni Liste ID si: 2585460285512 |
Aynı bellek bölgesini işaret ettiğini gördük. Şimdi yeni liste üzerine bir ekleme işlemi yapalım.
1 2 3 4 5 6 |
yeni_list.append(["Yeni liste", -67, 23]) print('Eski Liste:', eski_list) print('Eski liste ID si:', id(eski_list)) print('Yeni Liste:', yeni_list) print('Yeni Liste ID si:', id(yeni_list)) |
1 2 3 4 |
Eski Liste: [[10, 20.2, 30], [-40, 50, 60], [70, 80, 9.9], ['Yeni liste', -67, 23], ['Yeni liste', -67, 23]] Eski liste ID si: 2585460092168 Yeni Liste: [[10, 20.2, 30], [-40, 50, 60], [70, 80, 9.9], ['Yeni liste', -67, 23], ['Yeni liste', -67, 23]] Yeni Liste ID si: 2585460092168 |
Görüldüğü gibi eklenen yeni verilerden sadece yeni_list değil aynı zamanda eski_list etkilenmiştir. Çünkü “=” ifadesi nesnelerin adreslerini aktarır.
16. 1. Kopyalama işlemi
Bazen orijinal değerleri kaybetmeden değişkeninizin bir kopyasına ihtiyaç duyabilirsiniz ve tabii ki yapılan bir değişiklik orijinal verinin bozulmasını istemezsiniz. Bunun için kendiniz bir kopyalama fonksiyonu yazabilirsiniz, ancak Python bu durumu düşünmüş ve size iki farklı kopyalama imkanı sunmuştur.
- Shallow
- Deep
Bunun için copy modülünü kullanacağız.
16. 1. 1. Shallow kopyalama
Shallow kopyalama işlemi değişkenin iç değerleri referans bazlı taşır. Ancak, değişkenin kendisi farklı bir adreste yer alır. Biraz kafalar karıştı. Örnek üzerinden gidelim.
1 2 3 4 5 6 7 8 9 10 11 12 |
import copy eski_list = [[10, 20.2, 30], [-40, 50, 60], [70, 80, 'Test']] yeni_list = copy.copy(eski_list) print('Eski Liste:', eski_list) print('Eski liste ID si:', id(eski_list)) print('Eski liste 1. eleman ID si', id(eski_list[0])) print('Yeni Liste:', yeni_list) print('Yeni Liste ID si:', id(yeni_list)) print('Yeni liste 1. eleman ID si', id(yeni_list[0])) |
1 2 3 4 5 6 |
Eski Liste: [[10, 20.2, 30], [-40, 50, 60], [70, 80, 'Test']] Eski liste ID si: 2585460288136 Eski liste 1. eleman ID si 2585460400776 Yeni Liste: [[10, 20.2, 30], [-40, 50, 60], [70, 80, 'Test']] Yeni Liste ID si: 2585460091848 Yeni liste 1. eleman ID si 2585460400776 |
Görüldüğü gibi eski ve yeni listelerin bellek adresleri farklıdır. Ancak, birinci elemanların bellek adresleri aynıdır. Şimdi yeni listeye bir append işlemi yapalım. Bakalım eski liste etkilenecek mi?
1 2 3 |
yeni_list.append(["Yeni liste", -67, 23]) print('Eski liste:', eski_list) print('Yeni Liste:', yeni_list) |
1 2 |
Eski liste: [[10, 20.2, 30], [-40, 50, 60], [70, 80, 'Test']] Yeni Liste: [[10, 20.2, 30], [-40, 50, 60], [70, 80, 'Test'], ['Yeni liste', -67, 23]] |
Yeni listeye append ile ekleme yaptığımızda eski liste bundan etkilenmez. Ancak, yeni_list[0][0] noktasını değiştirdiğimizde eski liste bundan etkilenir. Çünkü liste öğeleri kopyalama sırasında referans türünden taşınmıştır. Örneğin,
1 2 3 |
yeni_list[0][0] = "Güncelleme" print('Eski liste:', eski_list) print('Yeni Liste:', yeni_list) |
1 2 |
Eski liste: [['Güncelleme', 20.2, 30], [-40, 50, 60], [70, 80, 'Test']] Yeni Liste: [['Güncelleme', 20.2, 30], [-40, 50, 60], [70, 80, 'Test'], ['Yeni liste', -67, 23]] |
16. 1. 2. Deep kopyalama
Shallow kopyalama her ne kadar yeni bir bellek bölgesi açsa da, taşınan öğeler referans türünden taşınır. Şimdi tamamen hem değişken hem de değişken öğeleri için yeni bir bellek bölgesi açalım. Bu sayede ne append yaptığımızda ne de bir güncelleme yaptığımızda iki değişken birbirinden etkilenmesin.
1 2 3 4 5 6 7 8 9 10 11 12 |
import copy eski_list = [[10, 20.2, 30], [-40, 50, 60], [70, 80, 'Test']] yeni_list = copy.deepcopy(eski_list) print('Eski Liste:', eski_list) print('Eski liste ID si:', id(eski_list)) print('Eski liste 1. eleman ID si', id(eski_list[0])) print('Yeni Liste:', yeni_list) print('Yeni Liste ID si:', id(yeni_list)) print('Yeni liste 1. eleman ID si', id(yeni_list[0])) |
1 2 3 4 5 6 |
Eski Liste: [[10, 20.2, 30], [-40, 50, 60], [70, 80, 'Test']] Eski liste ID si: 2585460348808 Eski liste 1. eleman ID si 2585459745352 Yeni Liste: [[10, 20.2, 30], [-40, 50, 60], [70, 80, 'Test']] Yeni Liste ID si: 2585460403848 Yeni liste 1. eleman ID si 2585460349640 |
Hepsinin bellek bölgesinin birbirinden farklı olduğu görüyoruz. Şimdi bir append bir de güncelleme yapalım.
1 2 3 4 5 6 |
yeni_list.append(["Yeni liste", -67, 23]) print('Eski liste:', eski_list) print('Yeni Liste:', yeni_list) yeni_list[0][0] = "Güncelleme" print('Eski liste:', eski_list) print('Yeni Liste:', yeni_list) |
1 2 3 4 |
Eski liste: [[10, 20.2, 30], [-40, 50, 60], [70, 80, 'Test']] Yeni Liste: [[10, 20.2, 30], [-40, 50, 60], [70, 80, 'Test'], ['Yeni liste', -67, 23]] Eski liste: [[10, 20.2, 30], [-40, 50, 60], [70, 80, 'Test']] Yeni Liste: [['Güncelleme', 20.2, 30], [-40, 50, 60], [70, 80, 'Test'], ['Yeni liste', -67, 23]] |
Deepcopy sayesinde her iki liste tamamen birbirinden farklı oldu.