Diyelim ki üç arkadaşını selamlayacaksın:
print("*" * 20)
print("Merhaba, ilker!")
print("*" * 20)
print("*" * 20)
print("Merhaba, ahmet!")
print("*" * 20)
# ... mehmet için bir daha kopyala 😩
Aynı kodu üç kez yazdın. Yarın çerçeveyi * yerine = yapmak istersen üç yeri düzelteceksin — birini unutursan program tutarsızlaşır. Fonksiyon bu derdi kökten çözer: tekrar eden işi bir kez tarif et, istediğin kadar kullan. Aslında yabancın da değil — print(), len(), type() hep birilerinin senin için yazdığı fonksiyonlardı. Bugün üretici tarafa geçiyorsun. 🏭
def (define = tanımla), bir kod bloğuna isim takar. Tarif defterine yeni bir yemek eklemek gibi:
def selam_ver(): # tarifin adı: selam_ver
print("Merhaba dünya!") # tarifin adımları (girintili!)
Sözdizimi üç parçadır: def + isim + parantez () + iki nokta :. Gövde, tıpkı if ve for'daki gibi girintiyle içeride yazılır.
def bloğu çalıştırıldığında ekrana hiçbir şey gelmez — Python tarifi sadece deftere kaydeder. Kod ancak fonksiyon çağrılınca çalışır. "Fonksiyonu yazdım ama bir şey olmuyor" şikâyetinin sebebi %99 budur: çağırmayı unutmuşsundur.def selam_ver():
print("Merhaba dünya!")
selam_ver() # → Merhaba dünya!
selam_ver() # → Merhaba dünya!
selam_ver() # → Merhaba dünya!
Tarif bir kez yazıldı, yemek üç kez pişti. Kodun tek gerçek kuralı: önce tanımla, sonra çağır — Python yukarıdan aşağı okur, henüz tanımlanmamış fonksiyonu tanımaz.
selam_ver (parantezsiz) fonksiyonu çalıştırmaz, sadece adından bahseder. print(selam_ver) dersen ekrana tuhaf bir <function selam_ver at 0x...> yazısı gelir. Çalıştıran şey parantezdir: selam_ver().Yukarıdaki fonksiyon hep aynı şeyi söylüyor. Paranteze bir parametre koyarsan fonksiyon dışarıdan malzeme alan bir makineye dönüşür:
def bana_selam_ver(isim): # isim = malzeme kapısı
print(f"Merhaba, {isim}!")
bana_selam_ver("ilker") # → Merhaba, ilker!
bana_selam_ver("ahmet") # → Merhaba, ahmet!
bana_selam_ver("mehmet") # → Merhaba, mehmet!
Çağrıda paranteze yazdığın değere argüman denir; içeride parametre adıyla yaşar. Birden fazla malzeme için virgülle sırala — çağrıdaki sıra, parametre sırasıyla eşleşir:
def dikdortgen_alan(en, boy):
print(en * boy)
dikdortgen_alan(3, 5) # en=3, boy=5 → 15
x, y yerine en, boy yazmak fonksiyonu okuyana (ve iki hafta sonraki sana) kendini anlattırır. Fonksiyon adları da fiil gibi iş anlatsın: selam_ver, alan_hesapla, cift_mi.Parametreye = ile yedek değer verebilirsin. Argüman gelirse o kullanılır, gelmezse yedek devreye girer — restorandaki "acı belirtilmezse orta acı" kuralı:
def sayi_gir(sayi=0):
print("Girilen sayı:", sayi)
sayi_gir(120) # → Girilen sayı: 120
sayi_gir(11) # → Girilen sayı: 11
sayi_gir() # → Girilen sayı: 0 ← yedek devrede!
Zorunlu ve varsayılanlı parametreler karışabilir; varsayılanlılar sona yazılır: def kdvli_fiyat(fiyat, oran=20):
print = camekana yazı asmak. Yoldan geçen okur ama eline bir şey geçmez.
return = müşterinin eline ürünü vermek. Değişkene koyar, üstünde hesap yaparsın.
def yaz(x):
print(x * 2) # ekrana yazar, ürün VERMEZ
def ver(x):
return x * 2 # ürün verir, ekrana YAZMAZ
a = yaz(5) # ekranda 10 belirir ama a = None 😱
b = ver(5) # ekran boş ama b = 10 💪
print(b + 3) # 13 — ürünle hesap yapabildim!
Ürün vermeyen fonksiyondan bir şey almaya çalışırsan eline Python'un "hiçlik" değeri None geçer. Sonucunu ileride kullanacağın her fonksiyonda return şart. Hem hesapla hem göster demek istiyorsan ikisini birleştir: print(ver(5)).
return'ün ikinci süper gücü: fonksiyonu o anda bitirir. Müfredattan asal kontrolü — bölen bulunduğu saniyede dava kapanır:
def asal_mi(sayi):
if sayi < 2:
return False # 0 ve 1 asal değil — erken çıkış!
for i in range(2, sayi):
if sayi % i == 0:
return False # bölen bulundu, döngü bile devam etmez
return True # buraya ulaştıysa bölen yok → asal
print(asal_mi(17)) # True
print(asal_mi(25)) # False
Bir fonksiyonun içinden başkasını çağırmak serbest — büyük programlar böyle kurulur: her parça tek iş yapar, karmaşık iş birleşimden doğar:
def kare(x):
return x * x
def kareler_toplami(a, b):
return kare(a) + kare(b) # hesabı parçalara devret
print(kareler_toplami(3, 4)) # 9 + 16 = 25
a*a + b*b yazmadık? Sonuç aynı olurdu ama kare() bir gün değişirse (örneğin sonucu yuvarlasın istersek) onu kullanan her fonksiyon bedavaya güncellenir. Tek yerde tanımla, her yerde kazan.print(1, 2, 3, 4, 5)'in istediği kadar değer kabul etmesi dikkatini çekti mi? Sırrı yıldızlı parametreler. Şimdilik sadece tanışıyoruz — derinlemesine ilerideki konularda:
def kullanici_kayit(ad, soyad, **ek_bilgiler):
print("Ad Soyad:", ad, soyad)
print("Ekstralar:", ek_bilgiler)
kullanici_kayit("ilker", "turan", meslek="öğretmen", sehir="İstanbul")
# Ad Soyad: ilker turan
# Ekstralar: {'meslek': 'öğretmen', 'sehir': 'İstanbul'}
*args → sınırsız sıralı argümanı demet (tuple) olarak toplar. **kwargs → sınırsız isimli argümanı sözlük (dict) olarak toplar. "Kaç malzeme geleceği belli olmayan makine" gördüğünde aklına yıldızlar gelsin, bu kadarı yeter. ⭐
def f(): sonuc = 5 yazıp dışarıda print(sonuc) dersen NameError alırsın. İçerideki değeri dışarı taşımanın resmi yolu zaten öğrendiğin şey: return.