Dictionary (Sözlük)
Dictionary (sözlük), Python'un en güçlü ve en sık kullanılan veri yapılarından biri. Her eleman bir anahtar-değer (key-value) çiftinden oluşur. Anahtar benzersizdir ve ona karşılık gelen değere anında erişim sağlar.
Gerçek hayattaki bir telefon rehberi düşün: İsmi (anahtar) biliyorsan, numarasını (değer) anında bulabilirsin. A'dan Z'ye sırayla aramana gerek yok — direkt "Ahmet" diyorsun, numara geliyor. İşte dictionary tam olarak bu: O(1) zaman karmaşıklığıyla anahtar üzerinden değere erişim. Bu onu listelerdeki O(n) aramaya kıyasla inanılmaz hızlı yapar.
Dictionary Oluşturma
# Süslü parantezle (en yaygın)
ogrenci = {
"isim": "Ahmet",
"yas": 25,
"sehir": "İstanbul",
}
# Boş dictionary
bos = {}
bos2 = dict()
# dict() constructor ile
ogrenci2 = dict(isim="Ayşe", yas=22, sehir="Ankara")
print(ogrenci2) # {'isim': 'Ayşe', 'yas': 22, 'sehir': 'Ankara'}
# Tuple listesinden
ciftler = [("a", 1), ("b", 2), ("c", 3)]
d = dict(ciftler)
print(d) # {'a': 1, 'b': 2, 'c': 3}
# zip ile
anahtarlar = ["isim", "yas", "sehir"]
degerler = ["Mehmet", 30, "İzmir"]
d = dict(zip(anahtarlar, degerler))
print(d) # {'isim': 'Mehmet', 'yas': 30, 'sehir': 'İzmir'}
# fromkeys: Tüm key'lere aynı değer
harfler = dict.fromkeys("abc", 0)
print(harfler) # {'a': 0, 'b': 0, 'c': 0}Key Kuralları
Dictionary key'leri hashable olmalıdır. Yani immutable tipler key olabilir:
# ✅ Geçerli key'ler
d = {
"string_key": 1,
42: 2,
3.14: 3,
(1, 2): 4, # Tuple hashable
True: 5,
None: 6,
frozenset({1, 2}): 7,
}
# ❌ Geçersiz key'ler
# d = {[1, 2]: "değer"} # TypeError: unhashable type: 'list'
# d = {{1, 2}: "değer"} # TypeError: unhashable type: 'set'
# d = {{"a": 1}: "değer"} # TypeError: unhashable type: 'dict'⚠️ Dikkat:
Trueve1,Falseve0Python'da eşit kabul edilir ve aynı hash'e sahiptir. Bu yüzden aynı key olarak davranırlar: ``python d = {True: "bool", 1: "int"} print(d) # {True: 'int'} — 1, True'nun üzerine yazdı!``
CRUD İşlemleri
Create & Read (Oluşturma & Okuma)
ogrenci = {"isim": "Ahmet", "yas": 25}
# Okuma — köşeli parantez
print(ogrenci["isim"]) # Ahmet
print(ogrenci["yas"]) # 25
# Olmayan key → KeyError!
# print(ogrenci["sinif"]) # KeyError: 'sinif'Update (Güncelleme)
# Mevcut değeri güncelle
ogrenci["yas"] = 26
print(ogrenci) # {'isim': 'Ahmet', 'yas': 26}
# Yeni key-value ekle (yoksa oluşturur)
ogrenci["sinif"] = "A"
print(ogrenci) # {'isim': 'Ahmet', 'yas': 26, 'sinif': 'A'}Delete (Silme)
ogrenci = {"isim": "Ahmet", "yas": 25, "sehir": "İstanbul"}
# del ile silme
del ogrenci["sehir"]
print(ogrenci) # {'isim': 'Ahmet', 'yas': 25}
# pop ile silme (değeri döndürür)
yas = ogrenci.pop("yas")
print(yas) # 25
print(ogrenci) # {'isim': 'Ahmet'}
# pop — olmayan key, varsayılan değer
sonuc = ogrenci.pop("telefon", "Bulunamadı")
print(sonuc) # Bulunamadı
# popitem — son eklenen key-value çiftini sil (Python 3.7+)
d = {"a": 1, "b": 2, "c": 3}
son = d.popitem()
print(son) # ('c', 3)
print(d) # {'a': 1, 'b': 2}
# clear — tümünü sil
d.clear()
print(d) # {}get() vs []: KeyError'dan Kaçınma
Bu çok önemli bir fark:
ogrenci = {"isim": "Ahmet", "yas": 25}
# [] — key yoksa HATA
# print(ogrenci["telefon"]) # KeyError: 'telefon'
# get() — key yoksa None döner (veya verdiğin varsayılan)
print(ogrenci.get("telefon")) # None
print(ogrenci.get("telefon", "Yok")) # Yok
print(ogrenci.get("isim")) # Ahmet
print(ogrenci.get("isim", "Bilinmiyor")) # Ahmet (key var, varsayılan kullanılmaz)Ne Zaman Hangisi?
# [] kullan: Key'in var olduğundan EMİNSEN
config = {"host": "localhost", "port": 8080}
port = config["port"] # Kesinlikle var
# get() kullan: Key olmayabilirse
kullanici = {"isim": "Ahmet"}
telefon = kullanici.get("telefon", "Belirtilmemiş")
# get() kullan: Döngü içinde güvenli erişim
for satir in veriler:
deger = satir.get("opsiyonel_alan", "varsayilan")setdefault(): Yoksa Ekle, Varsa Döndür
d = {"a": 1, "b": 2}
# Key varsa: mevcut değeri döndür (değiştirmez)
sonuc = d.setdefault("a", 999)
print(sonuc) # 1
print(d) # {'a': 1, 'b': 2} — değişmedi
# Key yoksa: ekle ve döndür
sonuc = d.setdefault("c", 3)
print(sonuc) # 3
print(d) # {'a': 1, 'b': 2, 'c': 3} — eklendi!setdefault özellikle gruplama yaparken kullanışlı:
# Öğrencileri sınıflarına göre grupla
ogrenciler = [
("Ahmet", "A"), ("Ayşe", "B"), ("Mehmet", "A"),
("Fatma", "B"), ("Ali", "A"),
]
siniflar = {}
for isim, sinif in ogrenciler:
siniflar.setdefault(sinif, []).append(isim)
print(siniflar)
# {'A': ['Ahmet', 'Mehmet', 'Ali'], 'B': ['Ayşe', 'Fatma']}Dictionary Metodları
keys(), values(), items()
ogrenci = {"isim": "Ahmet", "yas": 25, "sehir": "İstanbul"}
# keys() — anahtarlar
print(ogrenci.keys()) # dict_keys(['isim', 'yas', 'sehir'])
print(list(ogrenci.keys())) # ['isim', 'yas', 'sehir']
# values() — değerler
print(ogrenci.values()) # dict_values(['Ahmet', 25, 'İstanbul'])
# items() — anahtar-değer çiftleri (tuple olarak)
print(ogrenci.items()) # dict_items([('isim', 'Ahmet'), ...])Bu view nesneleri canlı — dict değişince otomatik güncellenir:
d = {"a": 1, "b": 2}
k = d.keys()
print(k) # dict_keys(['a', 'b'])
d["c"] = 3
print(k) # dict_keys(['a', 'b', 'c']) — otomatik güncellendi!update()
d1 = {"a": 1, "b": 2}
d2 = {"b": 20, "c": 3}
# Mevcut dict'i güncelle (çakışan key'lerde d2 kazanır)
d1.update(d2)
print(d1) # {'a': 1, 'b': 20, 'c': 3}
# Keyword argümanlarıyla da çalışır
d1.update(d=4, e=5)
print(d1) # {'a': 1, 'b': 20, 'c': 3, 'd': 4, 'e': 5}Döngü ile Dictionary
kisi = {"isim": "Ahmet", "yas": 25, "sehir": "İstanbul"}
# Sadece key'ler (varsayılan)
for key in kisi:
print(key)
# Key-value birlikte (en yaygın)
for key, value in kisi.items():
print(f"{key}: {value}")
# Sadece değerler
for value in kisi.values():
print(value)Dict Comprehension
Liste comprehension gibi, dict'ler için de tek satırda oluşturma:
# Temel
kareler = {x: x**2 for x in range(1, 6)}
print(kareler) # {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
# Koşullu
cift_kareler = {x: x**2 for x in range(1, 11) if x % 2 == 0}
print(cift_kareler) # {2: 4, 4: 16, 6: 36, 8: 64, 10: 100}
# Mevcut dict'ten dönüştürme
fiyatlar = {"elma": 5, "armut": 7, "muz": 3}
indirimli = {urun: fiyat * 0.9 for urun, fiyat in fiyatlar.items()}
print(indirimli) # {'elma': 4.5, 'armut': 6.3, 'muz': 2.7}
# Key-value ters çevirme
orijinal = {"a": 1, "b": 2, "c": 3}
ters = {v: k for k, v in orijinal.items()}
print(ters) # {1: 'a', 2: 'b', 3: 'c'}
# İki listeden dict
isimler = ["Ahmet", "Ayşe", "Mehmet"]
notlar = [85, 92, 78]
sonuclar = {isim: not_ for isim, not_ in zip(isimler, notlar)}
print(sonuclar) # {'Ahmet': 85, 'Ayşe': 92, 'Mehmet': 78}String İşlemlerinde Dict Comprehension
# Karakter frekansı
metin = "mississippi"
frekans = {harf: metin.count(harf) for harf in set(metin)}
print(frekans) # {'m': 1, 'i': 4, 's': 4, 'p': 2}
# Kelime uzunlukları
kelimeler = ["python", "java", "go", "rust", "javascript"]
uzunluklar = {k: len(k) for k in kelimeler}
print(uzunluklar)Nested Dictionary
Gerçek dünya verileri genellikle iç içe yapıdadır:
okul = {
"sinif_A": {
"ogretmen": "Ali Hoca",
"ogrenciler": [
{"isim": "Ahmet", "not": 85},
{"isim": "Ayşe", "not": 92},
]
},
"sinif_B": {
"ogretmen": "Fatma Hoca",
"ogrenciler": [
{"isim": "Mehmet", "not": 78},
{"isim": "Zeynep", "not": 88},
]
}
}
# Derin erişim
print(okul["sinif_A"]["ogretmen"]) # Ali Hoca
print(okul["sinif_A"]["ogrenciler"][0]["isim"]) # Ahmet
# Derin güncelleme
okul["sinif_A"]["ogrenciler"][0]["not"] = 90Güvenli Derin Erişim
# İç içe get — her seviyede güvenli
def derin_al(d, *keys, varsayilan=None):
for key in keys:
if isinstance(d, dict):
d = d.get(key, varsayilan)
else:
return varsayilan
return d
config = {"database": {"host": "localhost", "port": 5432}}
print(derin_al(config, "database", "host")) # localhost
print(derin_al(config, "database", "password")) # None
print(derin_al(config, "cache", "host")) # NoneNested Dict Döngüsü
notlar = {
"Ahmet": {"matematik": 85, "fizik": 72, "kimya": 90},
"Ayşe": {"matematik": 92, "fizik": 88, "kimya": 95},
"Mehmet": {"matematik": 78, "fizik": 65, "kimya": 80},
}
for ogrenci, dersler in notlar.items():
ortalama = sum(dersler.values()) / len(dersler)
print(f"{ogrenci}: {ortalama:.1f}")collections Modülü: defaultdict ve Counter
defaultdict
Normal dict'te olmayan bir key'e erişmek KeyError verir. defaultdict ise otomatik varsayılan değer oluşturur:
from collections import defaultdict
# Varsayılan int (0)
sayac = defaultdict(int)
kelimeler = ["elma", "armut", "elma", "muz", "elma", "armut"]
for kelime in kelimeler:
sayac[kelime] += 1 # Key yoksa otomatik 0 başlar
print(dict(sayac)) # {'elma': 3, 'armut': 2, 'muz': 1}
# Varsayılan list ([])
gruplar = defaultdict(list)
ogrenciler = [("A", "Ahmet"), ("B", "Ayşe"), ("A", "Mehmet"), ("B", "Fatma")]
for sinif, isim in ogrenciler:
gruplar[sinif].append(isim)
print(dict(gruplar)) # {'A': ['Ahmet', 'Mehmet'], 'B': ['Ayşe', 'Fatma']}
# Varsayılan set
benzersiz = defaultdict(set)
veriler = [("A", 1), ("B", 2), ("A", 1), ("A", 3), ("B", 2)]
for kategori, deger in veriler:
benzersiz[kategori].add(deger)
print(dict(benzersiz)) # {'A': {1, 3}, 'B': {2}}defaultdict vs setdefault:
# setdefault ile
d = {}
d.setdefault("key", []).append(1)
# defaultdict ile — daha temiz
d = defaultdict(list)
d["key"].append(1)Counter
Counter kelime/eleman sayımı için özelleştirilmiş bir dict:
from collections import Counter
# Listeden sayım
meyveler = ["elma", "armut", "elma", "muz", "elma", "armut"]
sayim = Counter(meyveler)
print(sayim) # Counter({'elma': 3, 'armut': 2, 'muz': 1})
# String'den harf frekansı
harfler = Counter("mississippi")
print(harfler) # Counter({'i': 4, 's': 4, 'p': 2, 'm': 1})
# En yaygın N eleman
print(harfler.most_common(2)) # [('i', 4), ('s', 4)]
# Aritmetik işlemler
c1 = Counter(a=3, b=1)
c2 = Counter(a=1, b=2)
print(c1 + c2) # Counter({'a': 4, 'b': 3})
print(c1 - c2) # Counter({'a': 2})
# Toplam
print(sayim.total()) # 6 (Python 3.10+)💡 İpucu: Bir listede eleman frekansı hesaplamak istiyorsan, for döngüsü yerine
Counterkullan. Hem daha kısa hem daha hızlı (C ile optimize edilmiş).
Dict Ordering ve Sıralama
Python 3.7+ Ekleme Sırası Garantisi
Python 3.7'den itibaren dictionary'ler ekleme sırasını korur. Bu bir uygulama detayı değil, dil spesifikasyonunun bir parçası:
d = {}
d["c"] = 3
d["a"] = 1
d["b"] = 2
for k, v in d.items():
print(k, v)
# c 3
# a 1
# b 2 (ekleme sırasında)Sıralama
d = {"banana": 3, "apple": 1, "cherry": 2}
# Key'e göre sıralı dict
sirali_key = dict(sorted(d.items()))
print(sirali_key) # {'apple': 1, 'banana': 3, 'cherry': 2}
# Value'ya göre sıralı dict
sirali_value = dict(sorted(d.items(), key=lambda x: x[1]))
print(sirali_value) # {'apple': 1, 'cherry': 2, 'banana': 3}
# Azalan sıra
sirali_azalan = dict(sorted(d.items(), key=lambda x: x[1], reverse=True))
print(sirali_azalan) # {'banana': 3, 'cherry': 2, 'apple': 1}Dict Merge (Birleştirme)
Unpacking ile (**) — Python 3.5+
d1 = {"a": 1, "b": 2}
d2 = {"b": 20, "c": 3}
# Birleştir — çakışmada sonraki kazanır
merged = {**d1, **d2}
print(merged) # {'a': 1, 'b': 20, 'c': 3}
# Üç dict birleştirme
d3 = {"d": 4}
merged = {**d1, **d2, **d3}
print(merged) # {'a': 1, 'b': 20, 'c': 3, 'd': 4}| Operatörü — Python 3.9+
d1 = {"a": 1, "b": 2}
d2 = {"b": 20, "c": 3}
# | ile yeni dict (orijinaller değişmez)
merged = d1 | d2
print(merged) # {'a': 1, 'b': 20, 'c': 3}
# |= ile yerinde güncelleme
d1 |= d2
print(d1) # {'a': 1, 'b': 20, 'c': 3}Karşılaştırma Tablosu
| Yöntem | Python | Yeni dict? | Orijinal? | |
|---|---|---|---|---|
{**d1, **d2} | 3.5+ | ✅ Evet | Değişmez | |
| `d1 \ | d2` | 3.9+ | ✅ Evet | Değişmez |
d1.update(d2) | Tümü | ❌ Hayır | d1 değişir | |
| `d1 \ | = d2` | 3.9+ | ❌ Hayır | d1 değişir |
Pratik Örnekler
Örnek 1: Basit Cache (Memoization)
cache = {}
def fibonacci(n):
if n in cache:
return cache[n]
if n <= 1:
sonuc = n
else:
sonuc = fibonacci(n - 1) + fibonacci(n - 2)
cache[n] = sonuc
return sonuc
print(fibonacci(50)) # 12586269025 — cache sayesinde hızlı
print(f"Cache boyutu: {len(cache)}") # 51Örnek 2: Kelime Frekans Analizi
from collections import Counter
metin = """
Python programlama dili güzel bir dil
Python ile programlama çok kolay
programlama öğrenmek eğlenceli
"""
# Temizle ve say
kelimeler = metin.lower().split()
frekans = Counter(kelimeler)
print("En sık 5 kelime:")
for kelime, sayi in frekans.most_common(5):
print(f" '{kelime}': {sayi} kez")Örnek 3: Veri Gruplama
from collections import defaultdict
siparisler = [
{"musteri": "Ahmet", "urun": "Laptop", "tutar": 15000},
{"musteri": "Ayşe", "urun": "Telefon", "tutar": 8000},
{"musteri": "Ahmet", "urun": "Mouse", "tutar": 200},
{"musteri": "Mehmet", "urun": "Klavye", "tutar": 500},
{"musteri": "Ayşe", "urun": "Kulaklık", "tutar": 1000},
{"musteri": "Ahmet", "urun": "Monitor", "tutar": 5000},
]
# Müşteriye göre grupla
musteri_siparisleri = defaultdict(list)
musteri_toplam = defaultdict(float)
for siparis in siparisler:
musteri = siparis["musteri"]
musteri_siparisleri[musteri].append(siparis["urun"])
musteri_toplam[musteri] += siparis["tutar"]
for musteri in musteri_siparisleri:
urunler = ", ".join(musteri_siparisleri[musteri])
toplam = musteri_toplam[musteri]
print(f"{musteri}: {urunler} (Toplam: {toplam:,.0f} TL)")Örnek 4: İki Dict Karşılaştırma
def dict_farklari(d1, d2):
"""İki dictionary arasındaki farkları bul."""
tum_keyler = set(d1) | set(d2)
farklar = {}
for key in tum_keyler:
if key not in d1:
farklar[key] = {"durum": "sadece d2'de", "deger": d2[key]}
elif key not in d2:
farklar[key] = {"durum": "sadece d1'de", "deger": d1[key]}
elif d1[key] != d2[key]:
farklar[key] = {"durum": "farklı", "d1": d1[key], "d2": d2[key]}
return farklar
eski = {"isim": "Ahmet", "yas": 25, "sehir": "İstanbul"}
yeni = {"isim": "Ahmet", "yas": 26, "email": "ahmet@mail.com"}
for key, bilgi in dict_farklari(eski, yeni).items():
print(f" {key}: {bilgi}")Performans Özellikleri
Dictionary Python'un en hızlı veri yapılarından biri — ama neden?
Hash Tablosu Nasıl Çalışır?
Dictionary, perde arkasında hash tablosu kullanır. Bir key eklediğinde Python:
Key'in hash değerini hesaplar (
hash(key))Bu hash'e göre bellekte bir konum belirler
Değeri o konuma yazar
Arama yaparken aynı adımları izler — hash'e göre konuma gider, değeri okur. Bu yüzden O(1).
# Hash değerlerini görelim
print(hash("isim")) # Sabit bir sayı
print(hash(42)) # 42 (küçük int'ler kendisine hash'lenir)
print(hash((1, 2))) # Tuple hashable
# ❌ Unhashable — hash hesaplanamaz
# hash([1, 2]) # TypeError: unhashable type: 'list'Gerçek Dünya Performansı
import time
# 1 milyon kayıt
n = 1_000_000
buyuk_dict = {f"key_{i}": i for i in range(n)}
buyuk_liste = [(f"key_{i}", i) for i in range(n)]
# Dict'te arama — O(1)
start = time.perf_counter()
_ = buyuk_dict["key_999999"]
dict_sure = time.perf_counter() - start
# Liste'de arama — O(n)
start = time.perf_counter()
for k, v in buyuk_liste:
if k == "key_999999":
break
liste_sure = time.perf_counter() - start
print(f"Dict arama: {dict_sure:.8f}s")
print(f"Liste arama: {liste_sure:.4f}s")
print(f"Dict {liste_sure/dict_sure:.0f}x daha hızlı!")Yaygın Hatalar
1. Döngüde Dictionary Değiştirme
d = {"a": 1, "b": 2, "c": 3}
# ❌ RuntimeError: dictionary changed size during iteration
# for key in d:
# if d[key] < 2:
# del d[key]
# ✅ Kopyası üzerinde dön
for key in list(d.keys()):
if d[key] < 2:
del d[key]
print(d) # {'b': 2, 'c': 3}
# ✅ Veya comprehension ile yeni dict
d = {k: v for k, v in d.items() if v >= 2}2. Mutable Default Key Tuzağı
# ❌ fromkeys ile mutable varsayılan — aynı listeyi paylaşır!
d = dict.fromkeys(["a", "b", "c"], [])
d["a"].append(1)
print(d) # {'a': [1], 'b': [1], 'c': [1]} — Hepsi aynı liste!
# ✅ Comprehension ile
d = {k: [] for k in ["a", "b", "c"]}
d["a"].append(1)
print(d) # {'a': [1], 'b': [], 'c': []}3. Key Olarak Kullanılamayan Tipler
# Listeler hashable olmadığı için key olamaz
# d = {[1, 2]: "değer"} # TypeError
# Çözüm: tuple'a çevir
d = {tuple([1, 2]): "değer"}
print(d[(1, 2)]) # değerİleri Teknikler
Dictionary View Operasyonları
d1 = {"a": 1, "b": 2, "c": 3}
d2 = {"b": 2, "c": 4, "d": 5}
# Key'lerin kesişimi
ortak_keyler = d1.keys() & d2.keys()
print(ortak_keyler) # {'b', 'c'}
# Key'lerin farkı
sadece_d1 = d1.keys() - d2.keys()
print(sadece_d1) # {'a'}
# Item'ların kesişimi (key VE value eşleşmeli)
ortak_items = d1.items() & d2.items()
print(ortak_items) # {('b', 2)}dict Subclassing Alternatifleri
from collections import OrderedDict, ChainMap
# OrderedDict — Python 3.7+ sonrası çoğunlukla gereksiz
# Ama move_to_end() gibi ekstra metodları var
od = OrderedDict(a=1, b=2, c=3)
od.move_to_end("a")
print(list(od.keys())) # ['b', 'c', 'a']
# ChainMap — birden fazla dict'i zincirleme ara
varsayilan = {"tema": "light", "dil": "tr", "font_size": 14}
kullanici = {"tema": "dark", "font_size": 16}
config = ChainMap(kullanici, varsayilan)
print(config["tema"]) # dark (kullanıcı ayarı)
print(config["dil"]) # tr (varsayılan)
print(config["font_size"]) # 16 (kullanıcı ayarı)💡 İpucu:
ChainMapaslında dict'leri birleştirmez — zincirleme arar. Bu, büyük dict'lerde kopyalama maliyetinden kurtarır ve değişikliklerin anında yansımasını sağlar.
Özet
Dictionary anahtar-değer çiftlerinden oluşur — key üzerinden O(1) erişim sağlar. Key'ler hashable (immutable) olmalıdır.
`get(key, default)` ile KeyError'dan kaçınırsın;
setdefault()yoksa ekler varsa döndürür — gruplama işlemlerinde çok kullanışlı.Dict comprehension (
{k: v for ...}) tek satırda dict oluşturur — filtreleme, dönüştürme ve ters çevirme için ideal.`defaultdict` ve `Counter` (collections modülü) yaygın dict pattern'larını basitleştirir — gruplama için defaultdict, sayım için Counter kullan.
Python 3.7+ ekleme sırasını garanti eder. Dict merge:
{**d1, **d2}(3.5+) veyad1 | d2(3.9+) ile birleştir.Döngüde dict değiştirme RuntimeError verir —
list(d.keys())kopyası üzerinde dön veya comprehension ile yeni dict oluştur.
AI Asistan
Sorularını yanıtlamaya hazır