İsimle erişmek
Listeler dersinde bir siparişi ["AM-101", "İzmir", 1499.9] diye tutmuştun. Üç ay sonra siparis[2] gördüğünde bunun tutar olduğunu hatırlayacak mısın? Sözlük (dictionary, dict) her değere bir anahtar (key) verir: siparis["tutar"]. Anadolu Market'in müşteri kaydı, Ilgaz Bank'ın hesap bilgisi, bir API'den dönen yanıt: iş dünyasındaki verinin büyük kısmı bu biçimdedir.
musteri = {
"no": "M-101",
"ad": "Ayşe Yılmaz",
"sehir": "İzmir",
"bakiye": 12500.0,
"aktif": True,
}
print(musteri["ad"])
print(musteri["bakiye"] + 500)
print(len(musteri), "alan")
print(type(musteri))
Süslü parantez içinde anahtar: değer çiftleri. Anahtar genelde metindir ama sayı ve demet de olabilir; değişmez olması yeter. Değer ise her şey olabilir: sayı, metin, liste, hatta başka bir sözlük. Python 3.7'den beri sözlük, anahtarların ekleme sırasını korur.
Okuma: köşeli parantez mi get mi?
Var olmayan anahtarı köşeli parantezle istersen KeyError alırsın. get ise bulamazsa None ya da senin verdiğin varsayılanı döndürür ve programı durdurmaz.
musteri = {"no": "M-101", "ad": "Ayşe Yılmaz", "sehir": "İzmir"}
print(musteri.get("sehir"))
print(musteri.get("telefon")) # None
print(musteri.get("telefon", "kayıtlı değil"))
print("telefon" in musteri) # anahtar var mı?
print("ad" in musteri)
try:
print(musteri["telefon"])
except KeyError as hata:
print("KeyError:", hata)
Kural: anahtarın kesin var olduğunu biliyorsan köşeli parantez (hata alırsan bu gerçek bir sorundur ve görmek istersin). Eksik olabilecek alanlarda get. in operatörü sözlükte anahtarları arar, değerleri değil.
Ekleme, güncelleme, silme
hesap = {"no": "TR-5501", "bakiye": 10000}
hesap["sahip"] = "Mehmet Kaya" # yeni anahtar ekle
hesap["bakiye"] = hesap["bakiye"] - 750 # değeri değiştir
hesap["bakiye"] += 2000 # kısayol
print(hesap)
hesap.update({"sube": "Konak", "bakiye": 11250}) # toplu güncelle
print(hesap)
silinen = hesap.pop("sube") # anahtarı çıkar, değeri döndür
print(silinen, hesap)
del hesap["sahip"]
print(hesap)
print(hesap.pop("yok", "bulunamadı")) # varsayılanlı pop
Aynı anahtara ikinci kez atama yapmak üzerine yazar; sözlükte anahtar tekrarı yoktur. update başka bir sözlükten alanları alır: var olanları günceller, olmayanları ekler. pop ve del siler; pop değeri geri verdiği için daha sık kullanılır.
| İşlem | Yazım | Eksik anahtarda |
|---|---|---|
| Oku | d["k"] | KeyError |
| Güvenli oku | d.get("k", varsayilan) | varsayılan döner |
| Ekle / güncelle | d["k"] = v | eklenir |
| Toplu güncelle | d.update(baska) | eklenir |
| Sil ve al | d.pop("k") | KeyError (varsayılan verilmezse) |
| Sil | del d["k"] | KeyError |
| Var mı? | "k" in d | False |
keys, values, items
Sözlüğün üç görünümü vardır: anahtarlar, değerler ve çiftler. Bunlar liste gibi gezilebilir; döngüler dersinde her gün kullanacaksın. Şimdilik listeye çevirip bakalım:
fiyatlar = {"kahve makinesi": 1499.9, "kalem": 2.5, "defter": 45}
print(list(fiyatlar.keys()))
print(list(fiyatlar.values()))
print(list(fiyatlar.items()))
print("Toplam:", sum(fiyatlar.values()))
print("En pahalı:", max(fiyatlar, key=fiyatlar.get))
urun, fiyat = list(fiyatlar.items())[0] # demet açma!
print(urun, fiyat)
items her çifti bir demet olarak verir; demet açmayı öğrendiğin için urun, fiyat = ... yazabildin. max(fiyatlar, key=fiyatlar.get) kalıbı "değeri en büyük olan anahtarı bul" demektir ve raporlarda çok geçer.
İç içe sözlük ve JSON'a hazırlık
Bir müşterinin birden fazla siparişi, bir siparişin birden fazla ürünü var. Değer olarak liste ve sözlük kullanarak hiyerarşi kurarsın:
musteri = {
"no": "M-101",
"ad": "Ayşe Yılmaz",
"adres": {"sehir": "İzmir", "ilce": "Konak", "posta": "35220"},
"siparisler": [
{"kod": "AM-101", "tutar": 1499.9, "teslim": True},
{"kod": "AM-103", "tutar": 89.5, "teslim": False},
],
}
print(musteri["adres"]["sehir"])
print(musteri["siparisler"][0]["kod"])
print(musteri["siparisler"][-1]["teslim"])
musteri["adres"]["ilce"] = "Bornova"
musteri["siparisler"].append({"kod": "AM-110", "tutar": 250, "teslim": False})
print(len(musteri["siparisler"]), "sipariş")
import json
print(json.dumps(musteri, ensure_ascii=False, indent=2)[:80])
Zincirleme köşeli parantez derinlere iner: önce adres sözlüğü, sonra içindeki şehir. Son satırlardaki json modülü bu yapıyı metne çevirir. JSON, web servislerinin ve yapılandırma dosyalarının ortak dilidir ve Python sözlüğüyle neredeyse birebir aynı görünür: süslü parantez, anahtar-değer, listeler. Sözlüğü iyi kavradıysan JSON'ı zaten biliyorsun; JSON ve CSV dersinde dosyadan okuyup yazacağız.
yedek = musteri kopya değildir; musteri.copy() ise yalnızca dış sözlüğü kopyalar, içindeki adres sözlüğü ve sipariş listesi paylaşılır. İç içe yapıyı tamamen kopyalamak için copy.deepcopy kullan.Sayım kalıbı
Analistin en sık yazdığı kod parçalarından biri: bir listedeki her değerin kaç kez geçtiğini bulmak. Şehir bazlı sipariş adedi, ürün bazlı satış, hata türü bazlı log sayısı. Sözlük bunun için biçilmiş kaftan; anahtar değer, değer ise sayaç olur. Döngüyü henüz görmediğin için önce adım adım, sonra döngülü hâlini gösteriyorum:
sehirler = ["İzmir", "Ankara", "İzmir", "Bursa", "İzmir", "Ankara"]
sayim = {}
sayim["İzmir"] = sayim.get("İzmir", 0) + 1 # ilk kez: 0 + 1
sayim["Ankara"] = sayim.get("Ankara", 0) + 1
sayim["İzmir"] = sayim.get("İzmir", 0) + 1 # ikinci kez: 1 + 1
print(sayim)
sayim = {}
for sehir in sehirler: # döngü: her şehir için aynı satır
sayim[sehir] = sayim.get(sehir, 0) + 1
print(sayim)
print("En çok:", max(sayim, key=sayim.get))
Kalıbın kalbi tek satır: sayim[x] = sayim.get(x, 0) + 1. get'in varsayılanı 0 olduğu için ilk karşılaşmada hata çıkmaz. Döngüler dersinde for satırını tam olarak anlayacaksın; şimdilik "listenin her elemanı için bu satırı çalıştır" diye oku. Aynı işi hazır yapan collections.Counter da var; Orta seviyede göreceksin.
toplam[sehir] = toplam.get(sehir, 0) + tutar. Şehir bazlı ciro bu tek satırdır.ciro[("İzmir", 2025)].Sözlükleri birleştirmek
İki kaynaktan gelen ayarları ya da fiyat listelerini birleştirmek günlük iştir. Python 3.9'dan beri bunun için | (yeni sözlük) ve |= (yerinde) operatörleri var. Aynı anahtar iki tarafta da varsa sağdaki kazanır. Eski kodlarda aynı işi {**a, **b} ya da a.update(b) ile görürsün.
varsayilan = {"para_birimi": "TL", "kdv": 0.20, "kargo": 49.9}
kampanya = {"kargo": 0, "indirim": 0.10}
ayar = varsayilan | kampanya # yeni sözlük, sağdaki kazanır
print(ayar)
print(varsayilan) # değişmedi
eski_yol = {**varsayilan, **kampanya} # aynı sonuç
print(ayar == eski_yol)
varsayilan |= {"kdv": 0.10} # yerinde güncelleme
print(varsayilan["kdv"])
Birleştirme üzerine yazar, toplamaz. İki deponun stoklarını toplamak istiyorsan döngüyle get(..., 0) kalıbını kullanırsın; aşağıdaki alıştırmalarda bunu yapacaksın.
Silmenin dört yolu
| Yöntem | Dönen değer | Anahtar yoksa | Ne zaman? |
|---|---|---|---|
del d[k] | - | KeyError | Anahtarın var olduğundan eminsen |
d.pop(k) | Silinen değer | KeyError | Değeri kullanacaksan |
d.pop(k, varsayilan) | Değer ya da varsayılan | Varsayılanı döndürür | "Varsa al ve sil" |
d.popitem() | Son eklenen (anahtar, değer) | Boşsa KeyError | Yığın gibi tüketmek |
d.clear() | None | - | Hepsini boşalt |
kuponlar = {"YAZ10": 10, "ILK50": 50}
indirim = kuponlar.pop("YAZ10", 0) # kullanılan kupon silinir
print(indirim, kuponlar)
print(kuponlar.pop("SAHTE", 0)) # yoksa 0, hata yok
sepet = {"çay": 2, "kahve": 1}
print(sepet.popitem()) # en son eklenen: ('kahve', 1)
Gezerken değiştirme tuzağı
Bir sözlüğü for ile gezerken ona anahtar ekler ya da silersen Python RuntimeError: dictionary changed size during iteration verir. Çözüm: anahtarların bir kopyası üzerinde gez (list(d)) ya da silinecekleri önce topla, sonra sil. Var olan anahtarın değerini değiştirmek ise güvenlidir.
stok = {"çay": 0, "kahve": 5, "şeker": 0, "su": 12}
for urun in list(stok): # kopya üzerinde gez
if stok[urun] == 0:
del stok[urun]
print(stok)
for urun in stok: # değer güncellemek serbest
stok[urun] += 10
print(stok)
Görünümler (views) canlıdır ve küme gibi davranır
keys(), values(), items() kopya değil, sözlüğe açılan canlı pencerelerdir (view): sözlük değişince görünüm de değişir. Ayrıca keys() küme işlemlerini destekler; iki fiyat listesini karşılaştırırken kümeye çevirmene bile gerek kalmaz.
eski = {"çay": 120, "kahve": 340, "kek": 90}
yeni = {"çay": 125, "kahve": 340, "su": 15}
anahtarlar = yeni.keys()
print("Eklenen:", anahtarlar - eski.keys())
print("Kalkan:", eski.keys() - anahtarlar)
ortak = sorted(eski.keys() & anahtarlar)
print("Fiyatı değişen:", [u for u in ortak if eski[u] != yeni[u]])
yeni["süt"] = 40
print(len(anahtarlar)) # görünüm güncellendi: 4
Son satırdaki köşeli parantezli tek satırlık döngü bir liste comprehension'dır; Comprehension dersinde ayrıntılı göreceksin. Sözlük comprehension'ı da ({u: f * 1.2 for u, f in fiyat.items()}) orada.
Değerde arama yavaştır
"İzmir" in musteri yalnızca anahtarlara bakar ve karma (hash) sayesinde neredeyse anında yanıt verir. "İzmir" in musteri.values() ise listedeki gibi baştan sona tarar. Değere göre sık arama yapıyorsan, ters sözlüğü bir kez kurup sonra anahtarla aramak çok daha hızlıdır. Örneğin müşteri numarası → e-posta sözlüğün varsa ve sürekli "bu e-posta kimin?" diye soruyorsan, e-posta → müşteri numarası sözlüğünü bir kez üret.
eposta = {"M-1": "ayse@ornek.com", "M-2": "can@ornek.com"}
print("can@ornek.com" in eposta) # False: anahtarlara bakar
print("can@ornek.com" in eposta.values()) # True ama yavaş tarama
kimin = {}
for no, adres in eposta.items():
kimin[adres] = no
print(kimin["can@ornek.com"]) # hızlı ters arama
İç içe sözlüklerde güvenli erişimi (.get zinciri) ve derin kopyayı İç içe veri yapıları dersinde ayrıntılı göreceksin; buradaki kalıplar o dersin temelidir.
Değere göre sıralamak ve ilk N
Sözlük ekleme sırasını korur ama kendisi sıralanmaz. "En çok satan 3 ürün" için öğeleri (items()) değere göre sıralarsın. İki kısa yol var: anahtarları key=d.get ile sıralamak ya da çiftleri bir anahtar fonksiyonla sıralamak. Eşitlik kuralı gerekiyorsa demet anahtar kullan.
satis = {"çay": 120, "kahve": 340, "su": 120, "kek": 210}
print(sorted(satis, key=satis.get, reverse=True)[:3])
def adet_sonra_ad(cift):
urun, adet = cift
return (-adet, urun) # adet azalan, eşitlikte ad artan
for urun, adet in sorted(satis.items(), key=adet_sonra_ad):
print(f"{urun:<6}{adet:>5}")
Ters çevirme ve gruplama
Sözlüğü ters çevirmek (değer → anahtar) değerler benzersizse tek döngüdür. Değerler tekrar ediyorsa bilgi kaybolmasın diye her değere bir liste bağlarsın; bu da gruplama kalıbıdır. setdefault(k, []) anahtar yoksa boş listeyi koyup döndürür, varsa var olanı döndürür.
bolge = {"İzmir": "Ege", "Manisa": "Ege", "Ankara": "İç Anadolu", "Konya": "İç Anadolu", "Bursa": "Marmara"}
gruplar = {}
for sehir, b in bolge.items():
gruplar.setdefault(b, []).append(sehir)
print(gruplar)
dict.fromkeys(["İzmir", "Ankara"], []) her anahtara aynı listeyi bağlar: birine eklediğin herkese görünür. Değişebilir varsayılan gerekiyorsa setdefault ya da Collections dersinde göreceğin defaultdict(list) kullan. Sayım için hazır araç collections.Counter da o derste.{"a": 1, "b": 2} == {"b": 2, "a": 1} True'dur. Testlerde sözlükleri doğrudan == ile karşılaştırabilirsin; sıralama ancak yazdırırken önemlidir.varsayilan | dosya | ortam birleştirmesidir; sağdaki kazanır. Fiyat ya da stok listesi senkronizasyonunda da ilk iş iki sözlüğün anahtar farkını (eklenen/kalkan) ve ortak anahtarlarda değeri değişenleri çıkarmaktır.Sözlük neden hızlı?
Sözlük, kümeyle aynı karma tablo (hash table) yapısını kullanır. Anahtarın karması hesaplanır ve değer doğrudan o adreste aranır; sözlük bir milyon kayıt da tutsa okuma süresi değişmez. Listede "no'su M-101 olan müşteri" aramak baştan sona taramadır. Bu yüzden kayıtları numarayla erişilecekse liste değil sözlükte tut: musteriler["M-101"].
setdefault ve defaultdict
Sayım kalıbındaki get(x, 0) yerine sayim.setdefault(x, 0) da yazılır; anahtar yoksa ekler ve değeri döndürür. Gruplama için collections.defaultdict(list) daha temizdir: gruplar[sehir].append(siparis) tek satırda, var mı diye bakmadan. Standart kütüphane dersinde bu araçları ayrıntılı ele alacağız.
Veri modeli olarak sözlük: sınırlar
Sözlük esnektir ama "ad" yerine yanlışlıkla "adi" yazarsan Python şikâyet etmez; sessizce yeni alan ekler. Büyük projelerde bu tür yazım hatalarını yakalamak için kayıtları dataclass ya da TypedDict ile tanımlarsın. Sözlük veri taşımak için, dataclass veri tanımlamak için. Orta seviyede bu ayrımı yaşayarak öğreneceksin.