ProgramlamaPython Geliştirici (middleware, backend, testler)

Python'da koleksiyonları nasıl doğru bir şekilde kopyalamalıyız, hangi durumlarda copy() yetersizdir ve neden, ne zaman derin kopyaya ihtiyaç vardır?

Hintsage yapay zeka asistanı ile mülakatları geçin

Cevap.

Sorunun geçmişi: Python'da nesnelerin (özellikle koleksiyonların — listeler, sözlükler) kopyalanması kritik öneme sahiptir: bir değişkene basit atama yapmak, bir kopya değil, yalnızca yeni bir referans oluşturur. copy() ve deepcopy() özel yöntemleri, yapıların birlikte kullanımında istenmeyen "yan etkileri" önlemek için ortaya çıktı.

Problem: İç içe koleksiyonlarla (liste içinde liste, sözlük içinde sözlük) çalışırken, basit copy() yalnızca kap container'ı kopyalar, ancak iç öğeleri kopyalamaz. Bu, iç içe öğelerin değiştirilmesinin tüm "kopyalarda" yansımasına neden olabilen zor yakalanan hatalara yol açabilir.

Çözüm: copy.copy() yüzeysel bir kopya (shallow copy) oluşturur — üst düzeyde yeni bir container ama içteki nesneler aynı kalır. copy.deepcopy() tüm iç nesneleri özyinelemeli olarak kopyalar.

Kod örneği:

import copy lst = [[1, 2], [3, 4]] shallow = copy.copy(lst) deep = copy.deepcopy(lst) lst[0][0] = 10 print(shallow) # [[10, 2], [3, 4]] — iç nesne değişti! print(deep) # [[1, 2], [3, 4]] — deepcopy orijinal durumu korudu

Ana özellikler:

  • Basit atama yalnızca referansı kopyalar, hiçbir kopyalama yok
  • .copy() (veya copy.copy()) "dıştaki" container'ı kopyalar, ancak içteki nesneleri kopyalamaz
  • .deepcopy() kopyaların tam bağımsızlığı için kullanılır

Yanıltıcı Sorular.

Bazen lst2 = lst[:] yazmak yeterli mi?

lst2 = lst[:] listeyi yüzeysel bir şekilde kopyalar, ancak iç nesneler (örneğin, listeler içindeki listeler) yine de aynıdır. Düz listeler için bu yeterlidir; iç içe yapılar için değildir.

Örnek:

lst = [[1], [2]] lst2 = lst[:] lst[0][0] = 99 print(lst2) # [[99], [2]] — iç nesne her iki "kopyada" değişti

Tüm koleksiyonlar için .copy() yöntemi aynı şekilde çalışır mı?

Hayır. Örneğin, dict.copy() yüzeysel kopyalama yapar, list.copy() yalnızca Python 3.3 ile gelmiştir, set için — set.copy() vardır. Kullanıcı nesneleri için .copy() desteği, uygulanan metoda bağlıdır.


Her yerde deepcopy ile yetinmek mümkün mü? Güvenli ve verimli mi?

Hayır. deepcopy, pahalı bir işlemdir: büyük yapılar üzerinde performans sorunlarına neden olabilir ve kopyalanamayan/kapalı veya standart dışı nesnelerde bozulabilir. deepcopy'i yalnızca gerçekten tamamen bağımsız, özyinelemeli kopyalama gerektiğinde kullanın.


Tipik hatalar ve anti-paternler

  • İç içe yapılarda derin kopya için yerine normal atama veya .copy() kullanmak
  • Tüm nesneler üzerinde sürekli deepcopy kullanmak (programı yavaşlatır)
  • Kopyalamayı desteklemeyen nesneleri (örneğin, dosyalar, akışlar) kopyalamaya çalışmak

Gerçek hayattan örnek

Olumsuz durum

Testlerde "sözlük içinde sözlük" kopyalamak için dict.copy() kullanıldı. Bu nedenle, bir kullanıcının iç yapısındaki değişiklikler, diğer testleri beklenmedik şekilde etkiledi (veriler küresel olarak değişti).

Artılar:

  • Hızlı
  • Basit

Eksiler:

  • Anlaşılması zor hatalar, ortam izolasyonunun kırılması

Olumlu durum

copy.deepcopy() uygulandı, belgelerde her nesnenin yapı özelliklerini ve içerik düzeyini tanımladık, büyük miktarlarda derin kopyalamaktan kaçındık, parçalar halinde "manuel" kopyalamaya yöneldik.

Artılar:

  • Ortamın şeffaflığı
  • Nesnelerin bağımsızlığı

Eksiler:

  • Yapının anlaşılmasını gerektirir
  • Büyük yapılar için çok daha fazla bellek ve işlem süresi tüketir