Comprehension ve Generator Expressions
Comprehension, Python'un en sevilen ve en "Pythonic" özelliklerinden biri. For döngüsü ile 5-6 satırda yaptığın işi tek satırda, hem daha okunabilir hem daha hızlı yapmanı sağlar. Liste, dictionary, set ve generator — dört farklı comprehension türü var ve hepsini bu derste öğreneceksin.
Bir fabrika montaj hattı düşün: Hammaddeler giriyor (iterable), her biri bir işlemden geçiyor (expression), bazıları eleniyor (filter), ve sonuçta bitmiş ürünler çıkıyor (yeni koleksiyon). Comprehension tam olarak bu: [işlem(malzeme) for malzeme in hammaddeler if kalite_kontrol(malzeme)]. Tek satırda girdi → işlem → filtre → çıktı.
List Comprehension
Temel Söz Dizimi
# Söz dizimi: [ifade for değişken in iterable]
kareler = [x**2 for x in range(10)]
print(kareler) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]Bu, şu for döngüsünün kısaltması:
kareler = []
for x in range(10):
kareler.append(x**2)Comprehension versiyonu:
Daha kısa (1 satır vs 3 satır)
Daha hızlı (C seviyesinde optimize edilmiş)
Daha okunabilir (amacı daha net ifade eder)
Koşullu (Filtreleme)
# [ifade for değişken in iterable if koşul]
cift_sayilar = [x for x in range(20) if x % 2 == 0]
print(cift_sayilar) # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
# Pozitif sayıları al
sayilar = [-3, 5, -1, 8, -2, 7, 0]
pozitifler = [x for x in sayilar if x > 0]
print(pozitifler) # [5, 8, 7]if-else ile (Dönüşüm)
Dikkat: filtre (if sonda) ile dönüşüm (if-else başta) farklı yerlerde:
# Filtre: if sonda → elemanı dahil et veya etme
sadece_ciftler = [x for x in range(10) if x % 2 == 0]
# [0, 2, 4, 6, 8]
# Dönüşüm: if-else başta → her eleman için karar ver
etiketler = ["çift" if x % 2 == 0 else "tek" for x in range(6)]
print(etiketler) # ['çift', 'tek', 'çift', 'tek', 'çift', 'tek']
# Mutlak değer
mutlak = [x if x >= 0 else -x for x in [-3, 5, -1, 8, -2]]
print(mutlak) # [3, 5, 1, 8, 2]Kural: Filtre if → sona yaz. Dönüşüm if-else → başa (ifade kısmına) yaz.
String İşlemlerinde
isimler = [" Ahmet ", "AYŞE", "mehmet", " FaTmA "]
# Temizle ve capitalize et
temiz = [isim.strip().capitalize() for isim in isimler]
print(temiz) # ['Ahmet', 'Ayşe', 'Mehmet', 'Fatma']
# Sadece 5+ harfli isimleri al
uzun_isimler = [isim for isim in temiz if len(isim) >= 5]
print(uzun_isimler) # ['Ahmet', 'Fatma']
# Her kelimeyi büyük harfe
metin = "python çok güzel bir dil"
kelimeler = [k.upper() for k in metin.split()]
print(kelimeler) # ['PYTHON', 'ÇOK', 'GÜZEL', 'BİR', 'DİL']Tip Dönüşümü
# String listesini int'e çevir
str_sayilar = ["1", "2", "3", "4", "5"]
int_sayilar = [int(s) for s in str_sayilar]
print(int_sayilar) # [1, 2, 3, 4, 5]
# Geçersiz değerleri filtrele
veriler = ["42", "merhaba", "17", "", "99", "abc"]
gecerli = [int(v) for v in veriler if v.isdigit()]
print(gecerli) # [42, 17, 99]Fonksiyon Çağrısı ile
import math
sayilar = [1, 4, 9, 16, 25]
kokler = [math.sqrt(x) for x in sayilar]
print(kokler) # [1.0, 2.0, 3.0, 4.0, 5.0]
# Lambda ile
carpim = [(lambda a, b: a * b)(x, x + 1) for x in range(5)]
print(carpim) # [0, 2, 6, 12, 20]Dict Comprehension
Sözlük oluşturmak için:
# Temel
kareler = {x: x**2 for x in range(1, 6)}
print(kareler) # {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
# 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)Koşullu Dict Comprehension
# Sadece geçen öğrenciler
notlar = {"Ahmet": 85, "Ayşe": 45, "Mehmet": 92, "Fatma": 55}
gecenler = {k: v for k, v in notlar.items() if v >= 60}
print(gecenler) # {'Ahmet': 85, 'Mehmet': 92}
# Fiyat dönüşümü + filtre
fiyatlar_usd = {"laptop": 999, "mouse": 25, "keyboard": 75, "monitor": 350}
kur = 32.5
pahaliler_tl = {
urun: fiyat * kur
for urun, fiyat in fiyatlar_usd.items()
if fiyat > 100
}
print(pahaliler_tl)
# {'laptop': 32467.5, 'monitor': 11375.0}String İşlemlerinde
# Karakter frekansı
metin = "mississippi"
frekans = {harf: metin.count(harf) for harf in set(metin)}
print(frekans) # {'m': 1, 's': 4, 'i': 4, 'p': 2}
# Kelime → uzunluk mapping
kelimeler = ["python", "java", "go", "rust", "javascript"]
uzunluklar = {k: len(k) for k in kelimeler}
print(uzunluklar)
# {'python': 6, 'java': 4, 'go': 2, 'rust': 4, 'javascript': 10}
# Environment variable parsing
env_str = "HOST=localhost;PORT=8080;DEBUG=true"
config = {
k: v for k, v in
(pair.split("=") for pair in env_str.split(";"))
}
print(config) # {'HOST': 'localhost', 'PORT': '8080', 'DEBUG': 'true'}Set Comprehension
Benzersiz elemanlardan oluşan set oluşturmak için:
# Temel
kareler = {x**2 for x in range(-5, 6)}
print(kareler) # {0, 1, 4, 9, 16, 25} (duplicate'lar otomatik temizlenir)
# Benzersiz kelime uzunlukları
metin = "the quick brown fox jumps over the lazy dog"
uzunluklar = {len(kelime) for kelime in metin.split()}
print(uzunluklar) # {3, 4, 5}
# Bir metindeki benzersiz sesli harfler
sesli = {h for h in "programming".lower() if h in "aeiou"}
print(sesli) # {'a', 'i', 'o'}Set comprehension özellikle benzersiz değerler çıkarmak istediğinde kullanışlı. list(set(liste_comprehension)) yerine direkt set comprehension yaz.
Generator Expression: Lazy Evaluation
Generator expression, list comprehension'ın tembel (lazy) versiyonu. Tüm elemanları bellekte tutmaz — her istendiğinde bir sonrakini hesaplar.
# List comprehension — tüm elemanları bellekte tutar
liste = [x**2 for x in range(1_000_000)] # ~8MB bellek
# Generator expression — neredeyse hiç bellek kullanmaz
gen = (x**2 for x in range(1_000_000)) # ~100 byte!Söz Dizimi
# Köşeli parantez [] → liste
# Normal parantez () → generator
gen = (x**2 for x in range(5))
print(gen) # <generator object <genexpr> at 0x...>
print(type(gen)) # <class 'generator'>
# next() ile tek tek al
print(next(gen)) # 0
print(next(gen)) # 1
print(next(gen)) # 4
# for ile tüket
for deger in gen:
print(deger, end=" ") # 9 16 (kalan elemanlar)Ne Zaman Generator Kullan?
# ✅ sum, min, max gibi tek geçişli fonksiyonlarda
toplam = sum(x**2 for x in range(1_000_000)) # Parantez gereksiz!
print(toplam)
# ✅ any, all
hepsi_pozitif = all(x > 0 for x in [1, 2, 3, 4])
en_az_biri_cift = any(x % 2 == 0 for x in [1, 3, 4, 7])
# ✅ Zincirlemede (pipeline)
dosya_satirlari = (satir.strip() for satir in open("veri.txt"))
bos_olmayan = (satir for satir in dosya_satirlari if satir)
buyuk_harf = (satir.upper() for satir in bos_olmayan)
# Hiçbir adımda tüm dosya belleğe yüklenmez!
for satir in buyuk_harf:
print(satir)Bellek Karşılaştırması
import sys
# List — tüm sonuçları bellekte tutar
liste = [x**2 for x in range(10000)]
print(f"Liste: {sys.getsizeof(liste):,} byte") # ~87,624 byte
# Generator — sadece formülü tutar
gen = (x**2 for x in range(10000))
print(f"Generator: {sys.getsizeof(gen)} byte") # 200 byte!Generator Tek Kullanımlık!
gen = (x for x in range(5))
# İlk kullanım — çalışır
print(list(gen)) # [0, 1, 2, 3, 4]
# İkinci kullanım — BOŞ!
print(list(gen)) # []Generator bir kez tüketilince biter. Tekrar kullanmak istiyorsan yeniden oluştur veya listeye çevir.
💡 İpucu: Genel kural: sonucu birden fazla kullanacaksan list comprehension, tek geçiş yeterliyse veya veri çok büyükse generator expression kullan.
sum(),max(),min(),any(),all(),"".join()gibi fonksiyonlara doğrudan generator ver — gereksiz liste oluşturma.
Nested Comprehension
İç İçe for (Düzleştirme)
# Matris → düz liste (flatten)
matris = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
duz = [eleman for satir in matris for eleman in satir]
print(duz) # [1, 2, 3, 4, 5, 6, 7, 8, 9]Okuma sırası: soldan sağa, normal for döngüsü gibi:
# Eşdeğer for döngüsü
duz = []
for satir in matris: # Dış for (ilk yazılan)
for eleman in satir: # İç for (sonra yazılan)
duz.append(eleman)Matris Transpoze
matris = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
# Satır ↔ Sütun değiştir
transpose = [[satir[j] for satir in matris] for j in range(len(matris[0]))]
print(transpose) # [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
# zip ile daha temiz
transpose2 = [list(sutun) for sutun in zip(*matris)]
print(transpose2) # [[1, 4, 7], [2, 5, 8], [3, 6, 9]]Karteziyen Çarpım
renkler = ["kırmızı", "mavi"]
bedenler = ["S", "M", "L"]
kombinasyonlar = [f"{renk}-{beden}" for renk in renkler for beden in bedenler]
print(kombinasyonlar)
# ['kırmızı-S', 'kırmızı-M', 'kırmızı-L', 'mavi-S', 'mavi-M', 'mavi-L']Koşullu Nested Comprehension
# Matristeki çift sayıları topla
matris = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
ciftler = [x for satir in matris for x in satir if x % 2 == 0]
print(ciftler) # [2, 4, 6, 8]
# İç içe liste oluşturma
matris_yeni = [[i * j for j in range(1, 4)] for i in range(1, 4)]
print(matris_yeni) # [[1, 2, 3], [2, 4, 6], [3, 6, 9]]Nested Dict Comprehension
# Çarpım tablosu (dict of dicts)
carpim = {
i: {j: i * j for j in range(1, 6)}
for i in range(1, 6)
}
print(carpim[3][4]) # 12
print(carpim[5][5]) # 25Walrus Operator (:=) Comprehension'da
Python 3.8'de gelen walrus operator, comprehension içinde hesaplama sonucunu hem kullanmanı hem atamanı sağlar:
# Hesapla, filtrele VE sonucu kullan
import math
sayilar = [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
# Karekökü hesapla, 5'ten büyükleri al
sonuclar = [
kok
for x in sayilar
if (kok := math.sqrt(x)) > 5
]
print(sonuclar) # [6.0, 7.0, 8.0, 9.0, 10.0]Walrus olmadan aynı hesaplamayı iki kez yapmak gerekirdi:
# ❌ Hesaplama tekrarı
sonuclar = [math.sqrt(x) for x in sayilar if math.sqrt(x) > 5]
# ✅ Walrus ile tek hesaplama
sonuclar = [kok for x in sayilar if (kok := math.sqrt(x)) > 5]Başka Örnekler
# Regex eşleşmelerini hem kontrol et hem al
import re
metinler = ["Python 3.12", "Java 21", "Go 1.21", "Rust 1.75"]
pattern = re.compile(r"(\w+)\s+([\d.]+)")
sonuclar = [
(m.group(1), m.group(2))
for metin in metinler
if (m := pattern.match(metin))
]
print(sonuclar)
# [('Python', '3.12'), ('Java', '21'), ('Go', '1.21'), ('Rust', '1.75')]
# Pahalı fonksiyon sonucunu cache'le
def pahali_hesaplama(x):
return x ** 3 + x ** 2 + x + 1
sonuclar = [
(x, sonuc)
for x in range(100)
if (sonuc := pahali_hesaplama(x)) % 7 == 0
]
print(f"7'ye bölünebilen sonuç sayısı: {len(sonuclar)}")Ne Zaman Comprehension, Ne Zaman For Döngüsü?
Comprehension Kullan ✅
Basit dönüşüm: Bir koleksiyonu başka bir koleksiyona çevirme
Filtreleme: Koşula göre eleman seçme
Tek ifade: İşlem tek bir expression ile ifade edilebiliyorsa
Yeni koleksiyon oluşturma: Sonuç bir liste/dict/set ise
# ✅ Basit dönüşüm
buyuk = [isim.upper() for isim in isimler]
# ✅ Filtreleme
pozitifler = [x for x in sayilar if x > 0]
# ✅ Mapping
fiyat_tl = {urun: fiyat * kur for urun, fiyat in fiyatlar.items()}For Döngüsü Kullan ✅
Yan etki (side effect): print, dosya yazma, API çağrısı
Karmaşık mantık: Çoklu koşul, try-except, çoklu adım
Accumulation: Toplam, sayaç gibi biriktirme işlemleri
Okunabilirlik bozuluyorsa
# ✅ For döngüsü — yan etki var (print)
for isim in isimler:
print(f"Merhaba, {isim}!")
# ❌ Comprehension ile yan etki — kötü pratik!
# [print(f"Merhaba, {isim}!") for isim in isimler] # Gereksiz liste oluşturur
# ✅ For döngüsü — karmaşık mantık
sonuclar = []
for dosya in dosyalar:
try:
veri = dosya_oku(dosya)
if veri:
sonuclar.append(isleme(veri))
except IOError:
logla(f"Hata: {dosya}")
# ✅ For döngüsü — biriktirme
toplam = 0
for sayi in sayilar:
toplam += sayi # sum() daha iyi ama örnek olarak⚠️ Dikkat — Aşırı Karmaşık Comprehension Anti-Pattern:
>
```python # ❌ BU NE?! Okunması imkansız result = [ transform(x, y) for x in range(10) if validate(x) for y in get_items(x) if check(x, y) and y not in seen and not (seen := seen | {y}) ]
>
# ✅ For döngüsü ile çok daha okunabilir result = [] seen = set() for x in range(10): if not validate(x): continue for y in get_items(x): if check(x, y) and y not in seen: seen.add(y) result.append(transform(x, y)) ```
>
Kural: Comprehension 1 satırda rahatça okunabiliyorsa kullan. 2-3 satıra yayılıyorsa belki tamam. Daha fazlaysa kesinlikle for döngüsüne geç.
Comprehension ile Yaygın Pattern'lar
Düzleştirme (Flatten)
# 2D → 1D
matris = [[1, 2], [3, 4], [5, 6]]
duz = [x for satir in matris for x in satir]
print(duz) # [1, 2, 3, 4, 5, 6]
# Düzensiz iç içe listeler
duzensiz = [[1, 2], [3], [4, 5, 6], [7]]
duz = [x for alt_liste in duzensiz for x in alt_liste]
print(duz) # [1, 2, 3, 4, 5, 6, 7]Gruplama
# Çift ve tekleri ayır
sayilar = range(1, 11)
cift_tek = {
"çift": [x for x in sayilar if x % 2 == 0],
"tek": [x for x in sayilar if x % 2 != 0],
}
print(cift_tek)
# {'çift': [2, 4, 6, 8, 10], 'tek': [1, 3, 5, 7, 9]}Zincirleme Dönüşüm (Pipeline)
# Ham veri → temiz, işlenmiş çıktı
ham_veriler = [" 42 ", "abc", " 17 ", "", " 99 ", "def", " 0 "]
# 1. Boşlukları temizle, 2. Sayı olmayanları filtrele, 3. int'e çevir, 4. Sıfırları atla
temiz = [
int(v.strip())
for v in ham_veriler
if v.strip() and v.strip().lstrip("-").isdigit() and int(v.strip()) != 0
]
print(temiz) # [42, 17, 99]Arayüz Dönüşümü (API Response)
# API'den gelen ham veri
api_yaniti = [
{"id": 1, "first_name": "John", "last_name": "Doe", "is_active": True},
{"id": 2, "first_name": "Jane", "last_name": "Smith", "is_active": False},
{"id": 3, "first_name": "Bob", "last_name": "Wilson", "is_active": True},
]
# İstediğimiz formata dönüştür
kullanicilar = [
{
"tam_isim": f"{k['first_name']} {k['last_name']}",
"aktif": k["is_active"],
}
for k in api_yaniti
if k["is_active"] # Sadece aktif olanlar
]
print(kullanicilar)
# [{'tam_isim': 'John Doe', 'aktif': True}, {'tam_isim': 'Bob Wilson', 'aktif': True}]Performans Karşılaştırması
import timeit
# List comprehension vs for + append
n = 1_000_000
# For döngüsü
def for_dongusu():
sonuc = []
for i in range(n):
sonuc.append(i ** 2)
return sonuc
# List comprehension
def comprehension():
return [i ** 2 for i in range(n)]
# map
def map_yontemi():
return list(map(lambda x: x ** 2, range(n)))
print(f"For döngüsü: {timeit.timeit(for_dongusu, number=10):.3f}s")
print(f"Comprehension: {timeit.timeit(comprehension, number=10):.3f}s")
print(f"map: {timeit.timeit(map_yontemi, number=10):.3f}s")Tipik sonuçlar:
For döngüsü: ~1.5s
Comprehension: ~1.0s (~33% daha hızlı)
map: ~1.2s
Comprehension genellikle for döngüsünden %20-50 daha hızlı. Çünkü Python optimizer'ı comprehension'ları daha verimli bytecode'a çevirir.
Pratik Örnekler
Örnek 1: CSV Benzeri Veri İşleme
ham_veri = [
"Ahmet,25,İstanbul,85",
"Ayşe,22,Ankara,92",
"Mehmet,30,İzmir,78",
"", # Boş satır
"Fatma,28,Bursa,88",
]
# Parse et, boş satırları atla
ogrenciler = [
dict(zip(["isim", "yas", "sehir", "not"], satir.split(",")))
for satir in ham_veri
if satir.strip()
]
# 80+ not alanları filtrele
basarili = [
o["isim"]
for o in ogrenciler
if int(o["not"]) >= 80
]
print(basarili) # ['Ahmet', 'Ayşe', 'Fatma']Örnek 2: Matris İşlemleri
# İki matrisin elemanları toplamı
A = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
B = [[9, 8, 7], [6, 5, 4], [3, 2, 1]]
C = [
[A[i][j] + B[i][j] for j in range(len(A[0]))]
for i in range(len(A))
]
print(C) # [[10, 10, 10], [10, 10, 10], [10, 10, 10]]Örnek 3: Kelime İndeksi
metin = "python güzel python harika güzel bir dil python harika"
kelimeler = metin.split()
# Her kelimenin geçtiği indeksler
indeks = {
kelime: [i for i, k in enumerate(kelimeler) if k == kelime]
for kelime in set(kelimeler)
}
print(indeks)
# {'python': [0, 2, 8], 'güzel': [1, 4], 'harika': [3, 7], ...}Örnek 4: Sınıf Verisi Dönüştürme
from collections import namedtuple
Ogrenci = namedtuple("Ogrenci", "isim yas not_")
ham = [("Ahmet", "25", "85"), ("Ayşe", "22", "92"), ("Mehmet", "30", "78")]
# Tuple → NamedTuple, string → int dönüşümü
ogrenciler = [
Ogrenci(isim, int(yas), int(not_))
for isim, yas, not_ in ham
]
# Dict'e çevir
ogrenci_dict = {o.isim: o._asdict() for o in ogrenciler}
print(ogrenci_dict)Özet
List comprehension
[ifade for x in iterable if koşul]— for döngüsünden %20-50 daha hızlı ve daha okunabilir.Dict comprehension
{k: v for k, v in ...}— sözlük oluşturma, dönüştürme ve filtreleme için ideal.Set comprehension
{ifade for x in iterable}— benzersiz elemanlar kümesi oluşturmak için kullan.Generator expression
(ifade for x in iterable)— lazy evaluation ile bellek dostu;sum(),any(),all()gibi tek geçişli fonksiyonlara doğrudan ver.Nested comprehension matris düzleştirme ve transpoze için kullanışlı — okuma sırası soldan sağa, normal for gibi.
Okunabilirlik kuralı: Comprehension 1-2 satırda rahat okunabiliyorsa kullan; karmaşıklaşıyorsa veya yan etki varsa for döngüsüne geç.
AI Asistan
Sorularını yanıtlamaya hazır