Python’da veri yapıları neden önemli?
Python’da aynı problemi birden fazla şekilde çözebilirsiniz; çoğu zaman farkı yaratan şey hangi veri yapısını seçtiğiniz olur. Listeler (list), sözlükler (dict) ve setler (set) günlük geliştirme işlerinde en sık karşınıza çıkan üç temel yerleşik (built-in) koleksiyondur. Bu yazıda her birini kopyalayıp çalıştırabileceğiniz kısa örneklerle ele alacağız.
Davranış ve metotları doğrulamak için resmi dokümantasyon iyi bir başlangıçtır: Built-in Types (stdtypes) ve Python Tutorial: Data Structures.
Hızlı karşılaştırma: list vs dict vs set
| Tip | Ne için ideal? | Sıralı mı? | Tekrara izin verir mi? | Değiştirilebilir mi (mutable)? |
|---|---|---|---|---|
| list | Sıralı koleksiyon, indeksle erişim | Evet | Evet | Evet |
| dict | Anahtar → değer eşlemesi | Python 3.7+: eklenme sırası dil seviyesinde garantidir (3.6: CPython ayrıntısı) | Anahtarlar benzersizdir | Evet |
| set | Benzersiz elemanlar, küme işlemleri | Hayır (sırasız) | Hayır | Evet |
Özelliklerin ayrıntıları için resmi referans: Python 3 stdtypes.
1) Listeler (list): sıralı ve değiştirilebilir koleksiyon
Liste, elemanların sırasını koruyan ve içerik üzerinde yerinde (in-place) değişiklik yapabildiğiniz bir koleksiyondur. İndeksleme ve dilimleme (slicing) günlük kullanımın temel parçalarıdır. Detaylar için: stdtypes: list ve Tutorial: Data Structures.
Liste oluşturma, indeksleme, dilimleme
Ne gösterir: Liste oluşturma, negatif indeks ve slicing.
# Oluşturma
nums = [10, 20, 30]
words = list(("hello", "python"))
# İndeksleme
first = nums[0] # 10
last = nums[-1] # 30
# Dilimleme (slicing)
subset = nums[0:2] # [10, 20]
copy_like = nums[:] # sığ kopya (shallow copy)
Çıktı/Notlar: nums[:] yeni bir liste üretir; ancak iç içe (nested) yapılar varsa bu kopya “sığ” kalır.
Sık kullanılan liste metotları
Gündelik işlerde en çok kullanılanlar: append, extend, insert, pop, remove, sort, reverse, copy. Resmi metot listesi: Data Structures.
Ne gösterir: Ekleme/çıkarma ve yerinde sıralama.
items = ["a", "b"]
items.append("c")
items.extend(["d", "e"])
items.insert(1, "X")
last = items.pop() # "e"
items.remove("X") # ilk eşleşeni siler
items.sort() # yerinde sıralar
items.reverse() # yerinde ters çevirir
Çıktı/Notlar: sort() listeyi yerinde değiştirir ve None döndürür. Sıralanmış bir kopya için sorted(items) kullanın.
List comprehension: kısa ve okunabilir dönüşümler
List comprehension, bir listeyi dönüştürmenin/filtrelemenin kompakt bir yoludur. Örnekler için: Tutorial: Data Structures. Okunabilirlik ve pratik notlar için: Real Python — List Comprehensions.
Ne gösterir: Dönüştürme, filtreleme, birlikte kullanım.
# 1) Dönüştürme: her elemanın karesi
squares = [x * x for x in range(6)]
# 2) Filtreleme: sadece çift sayılar
evens = [x for x in range(10) if x % 2 == 0]
# 3) Hem filtre hem dönüşüm
labels = [f"user_{i}" for i in range(1, 6) if i != 3]
Beklenen sonuç: squares 0–25 arası kareleri, evens çiftleri, labels ise “user_3” hariç etiketleri üretir.
Not: Performans hakkında genelleme yaparken dikkatli olun: bazı durumlarda list comprehension pratikte hızlı olabilir; ancak sonuçlar Python sürümüne, veri boyutuna ve iç işlemlere göre değişir. En sağlıklısı, kendi ortamınızda küçük bir timeit deneyi yapmaktır.
Listelerde yaygın tuzak: paylaşılan (aliased) referanslar
Listeler mutable olduğu için aynı listeyi birden fazla yere “paylaştırmak” beklenmedik yan etkiler yaratabilir. Bu, özellikle atama/kopyalama yaparken önem kazanır. Arka plan için: stdtypes ve pratik notlar için Real Python.
Ne gösterir: Aynı listeyi iki değişkenin işaret etmesi (aliasing) ve copy() ile yeni liste almak.
a = [1, 2, 3]
b = a # b ve a aynı listeyi işaret eder
b.append(4)
# a artık [1, 2, 3, 4]
# Yeni liste nesnesi (sığ kopya):
c = a.copy()
c.append(5)
# a değişmez, c değişir
Çıktı/Notlar: b = a bir kopya üretmez; aynı nesne üzerinde çalışırsınız. Kopya gerekiyorsa copy() ya da dilimleme gibi yaklaşımları bilinçli kullanın.
2) Sözlükler (dict): anahtar → değer haritaları
dict, bir anahtarın (key) bir değere (value) karşılık geldiği haritalama tipidir. Birçok senaryoda (ayarlar, sayımlar, özellikler, önbellekler) doğal seçimdir. Ana referans: stdtypes: dict.
Sıra notu (sürüm vurgusu): Dict’in eklenme sırasını koruması Python 3.7+ için dil seviyesinde garantidir; Python 3.6 için bu davranış CPython’ın bir uygulama ayrıntısı olarak görülür. Detaylar için: stdtypes.
Dict oluşturma ve güvenli okuma
Ne gösterir: [] ile okuma ve get() ile varsayılan değer.
user = {"id": 7, "name": "Ada"}
# Doğrudan erişim (anahtar yoksa KeyError oluşur):
name = user["name"]
# get() ile varsayılan değer:
age = user.get("age", 0) # age yoksa 0 döner
Çıktı/Notlar: Dışarıdan gelen/veri kalitesi belirsiz sözlüklerde get() ile okumak, kontrol akışını sadeleştirebilir.
İterasyon: keys(), values(), items()
Ne gösterir: Anahtar/değer/çiftler üzerinde dolaşma.
settings = {"theme": "dark", "lang": "tr"}
for key in settings.keys():
print(key)
for value in settings.values():
print(value)
for key, value in settings.items():
print(key, value)
Çıktı/Notlar: Pratikte çoğu zaman for key, value in d.items() okunabilir bir varsayılandır.
setdefault(): “yoksa oluştur” desenleri
setdefault() özellikle gruplama ve liste biriktirme işlerinde kullanışlıdır. Metot davranışı için: stdtypes: dict.
Ne gösterir: Uzunluğa göre gruplama (liste biriktirme).
words = ["hi", "python", "data", "set"]
groups = {}
for w in words:
groups.setdefault(len(w), []).append(w)
Beklenen sonuç: groups içinde anahtarlar uzunluk, değerler o uzunluktaki kelimeler listesi olur (ör. 4 → ["data", "set"]).
Alternatif olarak collections.defaultdict da tercih edilebilir; ancak bu yazı yerleşik tiplerle odakta kalır.
Dict comprehension: hızlı dönüştürmeler
Ne gösterir: Sayıların karelerini anahtar-değer olarak üretme.
d = {x: x * x for x in range(5)}
Beklenen sonuç: 0→0, 1→1, 2→4 … şeklinde bir eşleme oluşur.
Önemli kural: dict anahtarları hashable olmalı
dict anahtarı olarak kullanılan nesneler “hashable” olmalıdır. Bu yüzden list veya dict gibi mutable tipler anahtar olamaz; tuple gibi immutable tipler çoğu durumda uygundur. Kuralın arka planı için: stdtypes.
Ne gösterir: Uygun/uygunsuz anahtar örnekleri ve bir kenar durum.
# Uygun değil: list hashable değildir (anahtar olamaz)
# d1 = {[1, 2]: "x"}
# Uygun: tuple çoğu durumda anahtar olabilir
d2 = {(1, 2): "x"}
# Kenar durum: tuple immutable olsa da içinde hashable olmayan öğe varsa olmaz
# d3 = {([1, 2], 3): "x"}
Çıktı/Notlar: Böyle bir ihtiyaçta veriyi tamamen immutable bir temsile dönüştürmek (ör. sadece sayı/string içeren tuple) veya farklı bir anahtar stratejisi seçmek gerekir.
3) Setler (set): benzersiz elemanlar ve küme işlemleri
set, benzersiz öğeleri tutan ve matematiksel küme işlemlerini destekleyen bir koleksiyondur. Tanım ve operasyonlar için: stdtypes: set ve eğitim dokümanı: Python Tutorial — Data Structures.
Set oluşturma ve üyelik testi
Ne gösterir: Tekrar eklemenin etkisi ve üyelik kontrolü.
nums = {1, 2, 3}
nums.add(3) # zaten varsa küme aynı kalır
nums.add(4) # {1, 2, 3, 4}
exists = 2 in nums # True
Çıktı/Notlar: Üyelik testinde set/dict çoğu durumda pratiktir; büyük veri kararlarında ölçüm yapmak iyi bir alışkanlıktır.
Küme operasyonları: union, intersection, difference
Ne gösterir: Birleşim, kesişim, fark ve simetrik fark.
a = {1, 2, 3, 4}
b = {3, 4, 5}
union = a | b
intersect = a & b
diff = a - b
sym_diff = a ^ b
Beklenen sonuç: union {1,2,3,4,5}, intersect {3,4}, diff {1,2}, sym_diff {1,2,5}. (Set çıktılarında sıra garantisi olmadığını unutmayın.)
Aynı işlemleri metotlarla da yapabilirsiniz: a.union(b), a.intersection(b), a.difference(b), a.symmetric_difference(b). Ayrıntı için: stdtypes: set.
Set comprehension ve frozenset
Ne gösterir: Tekilleştirme ve immutable set (frozenset).
# Set comprehension: benzersiz kareler
sq = {x * x for x in [1, 2, 2, 3]}
# Değiştirilemez set: frozenset
fs = frozenset([1, 2, 3])
Çıktı/Notlar: frozenset immutable olduğu için bazı senaryolarda dict anahtarı veya başka setlerin elemanı olarak kullanılabilir. Tanım için: stdtypes.
Mutable vs immutable: pratikte neyi değiştirir?
Python’da bazı tipler değiştirilebilir (mutable), bazıları değiştirilemez (immutable) davranır. Bu fark iki yerde özellikle hissedilir:
- Fonksiyonlara parametre geçerken: Mutable nesne üzerinde yerinde değişiklik yapılırsa, çağıran taraf da bu değişimi görür.
- Hashing gereken yerlerde: dict anahtarı veya set elemanı olmak için hashable bir temsil gerekir (çoğu durumda immutable tipler).
Resmi davranışlar için: stdtypes. Pratik yorumlar için: Real Python.
Fonksiyonlarda yan etkiyi kontrol etme
Ne gösterir: Listeyi yerinde değiştiren fonksiyonun çağırana etkisi.
def add_tag(tags, tag):
tags.append(tag) # yerinde değişiklik
my_tags = ["python"]
add_tag(my_tags, "data")
# my_tags artık ["python", "data"]
Eğer yan etki istemiyorsanız, fonksiyon içinde kopya ile çalışabilirsiniz:
Ne gösterir: Kopya alarak yeni liste döndürme.
def add_tag_safely(tags, tag):
new_tags = tags.copy()
new_tags.append(tag)
return new_tags
my_tags = ["python"]
result = add_tag_safely(my_tags, "data")
# my_tags değişmez, result yeni listedir
Çıktı/Notlar: İç içe yapılar varsa sığ kopya her durumu çözmeyebilir; böyle senaryolarda veri modelini sade tutmak veya farklı bir yaklaşım seçmek gerekebilir.
Ne zaman hangisini seçmeliyim? (Mini karar rehberi)
- Sıra önemliyse ve aynı eleman birden fazla kez bulunabiliyorsa: list
- Bir şeyi anahtarla bulmak istiyorsanız (id → kayıt, isim → değer): dict
- Benzersiz elemanlar ve küme işlemleri (kesişim/fark) istiyorsanız: set
Kısa kontrol listesi
- Listelerde: kopya mı istiyorsunuz, yoksa aynı liste üzerinde mi çalışıyorsunuz? (Aliasing riskini düşünün.)
- Dict’te: Anahtarınız gerçekten hashable mı?
- Set’te: Çıktı sırası üzerine mantık kurmayın; set sırasızdır.
- Comprehension kullanırken: Okunabilirlik bozuluyorsa basit bir for döngüsü daha iyi olabilir.
Basit bir timeit iskeleti (isteğe bağlı)
Aşağıdaki iskelet, kendi ortamınızda küçük karşılaştırmalar yapmak için bir başlangıçtır. Sonuçlar; Python sürümü, işletim sistemi ve veri boyutuna göre değişebilir.
Ne gösterir: Belirli bir ifadeyi çok kez çalıştırıp süre ölçümü.
import timeit
setup = "data = list(range(10000))"
stmt = "[x * 2 for x in data]"
print(timeit.timeit(stmt=stmt, setup=setup, number=200))
Not: Gerçek hayattaki iş yükünüzü temsil eden veri ve işlemlerle ölçüm yapmaya çalışın.
Sonuç
List, dict ve set; Python’da hem öğrenmesi kolay hem de doğru kullanıldığında üretkenliği artıran temel veri yapılarıdır. Listeler sıralı dönüşümler için, dict’ler anahtar-temelli erişim için, set’ler benzersizlik ve küme işlemleri için güçlüdür. Mutable vs immutable farkını akılda tutarak kopyalama/yan etki konularını yönetebilir, comprehension’ları da okunabilirlik çizgisini aşmadan kullanabilirsiniz.
Kaynaklar ve ileri okuma
- Python Docs — Built-in Types (stdtypes)
- Python Tutorial — Data Structures
- Real Python — List Comprehensions
- Real Python — Python Data Structures (mutable/immutable pratikleri)