Python'ın `copy` Modülü
Bu makale, Python'ın copy modülünü açıklar.
Yüzeysel (shallow) ve derin (deep) kopyalar arasındaki farklara odaklanarak, nesne çoğaltmanın temel mekanizmalarından özel sınıflardaki uygulamalara kadar net bir açıklama ve pratik örnekler sunuyoruz.
YouTube Video
Python'ın copy Modülü
Python'un copy modülü, nesne çoğaltmayı (kopyalamayı) ele almak için standart modüldür. Amacımız, yüzeysel ve derin kopyalar arasındaki farkı anlamak ve özel nesneler için kopyalama davranışını kontrol edebilmektir.
Temeller: Yüzeysel kopya nedir?
Burada liste ve sözlük gibi değiştirilebilir (mutable) nesneler için yüzeysel kopyaların davranışını gösteriyoruz. Yüzeysel kopya yalnızca en üst düzeydeki nesneyi çoğaltır ve içindeki başvuruları (referansları) paylaşır.
1# Example: shallow copy with lists and dicts
2import copy
3
4# A nested list
5original = [1, [2, 3], 4]
6shallow = copy.copy(original)
7
8# Mutate nested element
9shallow[1].append(99)
10
11print("original:", original) # nested change visible in original
12print("shallow: ", shallow)Bu kodda, üst düzey liste çoğaltılır, ancak içteki alt listeler referansla paylaşılır; bu nedenle shallow[1].append(99) işlemi original içinde de yansır. Bu, yüzeysel kopyanın tipik bir davranışıdır.
Derin kopya nedir?
Derin kopya, nesneyi ve içindeki tüm başvuruları (referansları) özyinelemeli olarak çoğaltarak bağımsız bir nesne üretir. Karmaşık, iç içe geçmiş yapıları güvenli bir şekilde çoğaltmak istediğinizde bunu kullanın.
1# Example: deep copy with nested structures
2import copy
3
4original = [1, [2, 3], {'a': [4, 5]}]
5deep = copy.deepcopy(original)
6
7# Mutate nested element of the deep copy
8deep[1].append(100)
9deep[2]['a'].append(200)
10
11print("original:", original) # original remains unchanged
12print("deep: ", deep)Bu örnekte, deep üzerindeki değişiklikler original'ı etkilemez. deepcopy, tüm nesne grafiğini kopyalayarak bağımsız bir kopya (replika) üretir.
Hangisini kullanacağınıza nasıl karar verilir
Hangi kopyanın kullanılacağı, nesnenin yapısına ve amacınıza göre belirlenmelidir. İçteki değiştirilebilir öğelerdeki değişikliklerin özgün (orijinal) nesneyi etkilemesini istemiyorsanız, deepcopy uygundur. Bunun nedeni, tüm nesneyi özyinelemeli olarak çoğaltıp tamamen bağımsız bir kopya oluşturmasıdır.
Öte yandan, yalnızca en üst düzey nesneyi çoğaltmak yeterliyse ve hız ile bellek verimliliğini önemsiyorsanız, copy (yüzeysel kopya) daha uygundur.
- İçteki değiştirilebilir öğeleri değiştirdiğinizde özgünün değişmesini istemiyorsanız →
deepcopykullanın. - Yalnızca en üst düzeyi çoğaltmak yeterli ve performansı (hız/bellek) önceliklendirmek istiyorsanız →
copy(yüzeysel kopya) kullanın.
Yerleşik ve değiştirilemez (immutable) nesnelerin ele alınması
Değiştirilemez nesnelerin (ör. int, str ve içeriği değiştirilemez demetler/tuple'lar) genellikle kopyalanmasına gerek yoktur. copy.copy, uygun olduğunda aynı nesneyi döndürebilir.
1# Example: copying immutables
2import copy
3
4a = 42
5b = copy.copy(a)
6print(a is b) # True for small ints (implementation detail)
7
8s = "hello"
9t = copy.deepcopy(s)
10print(s is t) # True (strings are immutable)Değiştirilemez nesneleri kopyalamanın verimlilik açısından az fayda sağlaması nedeniyle, aynı nesne yeniden kullanılabilir. Bu, uygulama tasarımında nadiren endişelenmeniz gereken bir konudur.
Özel sınıflar: __copy__ ve __deepcopy__ tanımlama
Varsayılan kopyalama sınıfınız için beklediğiniz gibi değilse kendi kopyalama mantığınızı sağlayabilirsiniz. __copy__ ve __deepcopy__ tanımlarsanız, copy.copy ve copy.deepcopy bunları kullanır.
1# Example: customizing copy behavior
2import copy
3
4class Node:
5 def __init__(self, value, children=None):
6 self.value = value
7 self.children = children or []
8
9 def __repr__(self):
10 return f"Node({self.value!r}, children={self.children!r})"
11
12 def __copy__(self):
13 # Shallow copy: create new Node, but reuse children list reference
14 new = self.__class__(self.value, self.children)
15 return new
16
17 def __deepcopy__(self, memo):
18 # Deep copy: copy value and deepcopy each child
19 new_children = [copy.deepcopy(child, memo) for child in self.children]
20 new = self.__class__(copy.deepcopy(self.value, memo), new_children)
21 memo[id(self)] = new
22 return new__copy__ve__deepcopy__yöntemlerini uygulayarak, sınıfa özgü kopyalama davranışını esnek biçimde kontrol edebilirsiniz. Örneğin, bazı özniteliklerin aynı nesneye atıfta bulunması (paylaşması) gerekirken, diğer özniteliklerin tamamen yeni nesneler olarak çoğaltılması gereken durumları ele alabilirsiniz.__deepcopy__'ye iletilenmemobağımsız değişkeni, özyinelemeli kopyalama sırasında zaten işlenen nesneleri kaydeden ve döngüsel referansların neden olduğu sonsuz döngüleri önleyen bir sözlüktür.
1# Build tree
2root_node = Node('root', [Node('child1'), Node('child2')])
3
4shallow_copy = copy.copy(root_node) # shallow copy
5deep_copy = copy.deepcopy(root_node) # deep copy
6
7# Modify children
8# affects both root_node and shallow_copy
9shallow_copy.children.append(Node('child_shallow'))
10# affects deep_copy only
11deep_copy.children.append(Node('child_deep'))
12
13# Print results
14print("root_node:", root_node)
15print("shallow_copy:", shallow_copy)
16print("deep_copy:", deep_copy)- Bu kodda,
shallow_copydeğişkeni 'sığ kopya' yoluyla oluşturulur; bu nedenle nesnenin yalnızca üst düzeyi çoğaltılır ve içeride başvurduğu nesneler (bu durumdachildrenlistesi) orijinalroot_nodeile paylaşılır. Sonuç olarak,shallow_copy'ye yeni bir düğüm eklediğinizde, paylaşılanchildrenlistesi güncellenir ve değişiklikroot_node'un içeriğine de yansır. - Öte yandan,
deep_copydeğişkeni 'derin kopya' yoluyla oluşturulur; bu nedenle iç yapı özyinelemeli olarak çoğaltılır veroot_node'dan tamamen bağımsız bir ağaç üretilir. Bu nedenle,deep_copy'ye yeni bir düğüm ekleseniz bile, buroot_node'u etkilemez.
Döngüsel başvurular (özyinelemeli nesneler) ve memo'nun önemi
Karmaşık bir nesne grafiği kendine başvurduğunda (döngüsel başvurular), deepcopy, halihazırda kopyalanmış nesneleri izlemek ve sonsuz döngüleri önlemek için bir memo sözlüğü kullanır.
1# Example: recursive list and deepcopy memo demonstration
2import copy
3
4a = []
5b = [a]
6a.append(b) # a -> [b], b -> [a] (cycle)
7
8# deepcopy can handle cycles
9deep = copy.deepcopy(a)
10print("deep copy succeeded, length:", len(deep))- Dahili olarak
deepcopy, zaten çoğaltılmış nesnelere başvurmak içinmemo'yu kullanır; bu, döngüler var olduğunda bile güvenli kopyalamayı sağlar. Özyinelemeyi elle yaptığınızda benzer bir mekanizmaya ihtiyaç duyarsınız.
copyreg ve serileştirme tarzı özel kopyalama (ileri düzey)
Kitaplıklarla uyum içinde özel kopyalama davranışını kaydetmek istiyorsanız, nesnelerin nasıl (yeniden) oluşturulacağını kaydetmek için standart copyreg modülünü kullanabilirsiniz. Bu, karmaşık nesneler ve C uzantı türleri için yararlıdır.
1# Example: using copyreg to customize pickling/copy behavior (brief example)
2import copy
3import copyreg
4
5class Wrapper:
6 def __init__(self, data):
7 self.data = data
8
9def reduce_wrapper(obj):
10 # Return callable and args so object can be reconstructed
11 return (Wrapper, (obj.data,))
12
13copyreg.pickle(Wrapper, reduce_wrapper)
14
15w = Wrapper([1, 2, 3])
16w_copy = copy.deepcopy(w)
17print("w_copy.data:", w_copy.data)copyregkullanarak hempicklehem dedeepcopyyi etkileyen yeniden oluşturma kuralları sağlayabilirsiniz. Bu, ileri düzey bir API'dir ve çoğu durumda__deepcopy__yeterlidir.
Pratik uyarılar ve tuzaklar
copy modülünü kullanırken doğru davranışı sağlamak için dikkat edilmesi gereken birkaç önemli nokta vardır. Aşağıda, geliştirme sırasında karşılaşabileceğiniz yaygın tuzakları ve bunlardan nasıl kaçınacağınızı açıklıyoruz.
- Performans
deepcopy, önemli miktarda bellek ve CPU tüketebilir; bu yüzden gerçekten gerekli olup olmadığını dikkatlice değerlendirin. - Paylaşmak istediğiniz öğelerin ele alınması
Büyük önbellekler gibi bazı özniteliklerin paylaşımlı kalmasını istiyorsanız,
__deepcopy__içinde onların referanslarını kopyalamaktan özellikle kaçının. - Değiştirilemez iç durum İçeride değiştirilemez veri tutuyorsanız, kopyalama gereksiz olabilir.
- İş parçacıkları ve harici kaynaklar Soketler ve dosya tanıtıcıları gibi kopyalanamayan kaynakları kopyalamak ya anlamsızdır ya da hatalara yol açar; bu nedenle tasarım itibarıyla bunları kopyalamaktan kaçınmalısınız.
Pratik örnek: sözlükleri güvenle güncellemek için bir kalıp
Karmaşık bir yapılandırma nesnesini güncellerken, bu örnek özgün ayarları korumak için deepcopy kullanır.
1# Example: safely update a nested configuration using deepcopy
2import copy
3
4default_config = {
5 "db": {"host": "localhost", "ports": [5432]},
6 "features": {"use_cache": True, "cache_sizes": [128, 256]},
7}
8
9# Create a working copy to modify without touching defaults
10working = copy.deepcopy(default_config)
11working["db"]["ports"].append(5433)
12working["features"]["cache_sizes"][0] = 512
13
14print("default_config:", default_config)
15print("working:", working)deepcopy kullanarak, varsayılan ayarları bozma riski olmadan türetilmiş yapılandırmalar oluşturabilirsiniz. Bu, özellikle yapılandırmalar gibi iç içe geçmiş değiştirilebilir yapılarda faydalıdır.
En iyi uygulamalar
copy modülünü güvenli ve etkili bir şekilde kullanmak için aşağıdaki pratik yönergeleri akılda tutmak önemlidir.
- Değişikliklerin olup olmayacağına ve kapsamına göre yüzeysel ve derin kopya arasında seçim yapın.
- Beklenen davranışı elde etmek için özel sınıflarda
__copy__ve__deepcopy__uygulayın. - Derin kopyalar maliyetli olduğundan, mümkün olduğunda tasarım yoluyla kopyalama ihtiyacını azaltın. Diğer tekniklerin yanı sıra değiştirilemezliği ve açık klon yöntemlerini değerlendirin.
- Döngüsel başvurularla uğraşırken ya
deepcopy'den yararlanın ya da ellememobenzeri bir mekanizma sağlayın. - Dosya tanıtıcıları ve iş parçacıkları gibi harici kaynakların kopyalanmamasını sağlayacak şekilde tasarlayın.
Sonuç
copy modülü, Python'da nesne çoğaltma için standart araçtır. Yüzeysel ve derin kopyalar arasındaki farkları doğru biçimde anlayıp gerektiğinde özel kopyalama davranışını uygulayarak çoğaltmayı güvenli ve öngörülebilir şekilde gerçekleştirebilirsiniz. Tasarım aşamasında kopyalamanın gerçekten gerekli olup olmadığını ve nelerin paylaşılması gerektiğini netleştirerek gereksiz hatalardan ve performans sorunlarından kaçınabilirsiniz.
Yukarıdaki makaleyi, YouTube kanalımızda Visual Studio Code'u kullanarak takip edebilirsiniz. Lütfen YouTube kanalını da kontrol edin.