Fonksiyon Tanımlama, Parametreler ve Return Değerleri
Fonksiyon, belirli bir görevi yerine getiren, yeniden kullanılabilir kod bloklarıdır. Fonksiyonlar sayesinde kodlarımızı daha organize, okunabilir ve bakımı kolay hale getiririz.
Şu senaryoyu düşünün: Bir programda 5 farklı yerde alan hesaplaması yapmanız gerekiyor...
# 1. hesaplama
en1, boy1 = 5, 10
alan1 = en1 * boy1
print(f"Alan: {alan1}")
# 2. hesaplama (aynı kod tekrar!)
en2, boy2 = 8, 12
alan2 = en2 * boy2
print(f"Alan: {alan2}")
# 3. hesaplama (yine aynı kod!)
en3, boy3 = 3, 7
alan3 = en3 * boy3
print(f"Alan: {alan3}")
# 5 yer daha... 🤦
⚠️ Sorunlar:
def alan_hesapla(en, boy):
"""Dikdörtgen alanı hesaplar"""
return en * boy
# Şimdi her yerde kullan!
print(f"Alan: {alan_hesapla(5, 10)}")
print(f"Alan: {alan_hesapla(8, 12)}")
print(f"Alan: {alan_hesapla(3, 7)}")
# Formül değişirse?
# Sadece fonksiyonu düzelt!
# Tüm programda otomatik düzelir ✨
✅ Avantajlar:
Programlamadaki en önemli prensiplerden biri: "Kendini Tekrarlama!"
Bu prensip sayesinde:
Her fonksiyon tek bir iş yapar → Anlaması kolay, test etmesi kolay, değiştirmesi kolay!
def fonksiyon_adi(parametre1, parametre2):
"""Docstring - fonksiyonun açıklaması"""
# Fonksiyon gövdesi
sonuc = parametre1 + parametre2
return sonuc
Fonksiyon tanımlama anahtar kelimesi
Fonksiyonun benzersiz adı
Fonksiyona gönderilen değişkenler
Fonksiyonun döndürdüğü değer
En basit haliyle, hiç parametre almayan ve değer döndürmeyen bir fonksiyon:
def selamla():
"""Bu fonksiyon basit bir selamlama yapar"""
print("Merhaba Dünya!")
print("Python öğreniyorum!")
# Fonksiyonu çağırma
selamla()
print("---")
selamla() # Birden fazla kez çağırabiliriz
Fonksiyonlara dışarıdan veri göndererek daha esnek hale getirebiliriz:
def selamla_kisi(isim):
"""Belirtilen kişiye selamlar"""
print(f"Merhaba {isim}!")
print(f"{isim}, nasılsın?")
# Farklı argümanlarla çağırma
selamla_kisi("Ahmet")
print("---")
selamla_kisi("Ayşe")
print("---")
selamla_kisi("Mehmet")
return anahtar kelimesi, fonksiyonun bir değer döndürmesini sağlar:
def topla(a, b):
"""İki sayıyı toplar ve sonucu döndürür"""
sonuc = a + b
return sonuc
def kare_al(sayi):
"""Bir sayının karesini döndürür"""
return sayi * sayi
# Return değerlerini kullanma
toplam = topla(15, 25)
print(f"Toplam: {toplam}")
kare = kare_al(7)
print(f"7'nin karesi: {kare}")
# Return değerini doğrudan kullanma
print(f"5 + 8 = {topla(5, 8)}")
print(f"12'nin karesi: {kare_al(12)}")
# Return değerini başka işlemlerde kullanma
sonuc = topla(10, 20) + kare_al(5)
print(f"10+20 + 5^2 = {sonuc}")
return olmadan bir fonksiyon None döndürür.
print() ile return farklıdır! print() sadece ekrana yazar,
return ise değeri fonksiyondan çıkartır.
FUNCTION min_bul(liste):
min ← liste[0]
FOR her eleman IN liste:
IF eleman < min:
min ← eleman
END IF
END FOR
RETURN min
END FUNCTION
// Kullanım
sayilar ← [45, 23, 67, 12, 89]
sonuc ← min_bul(sayilar)
PRINT sonuc
def ortalama_hesapla(liste):
"""Listedeki sayıların ortalamasını hesaplar"""
if len(liste) == 0:
return 0
toplam = 0
for sayi in liste:
toplam += sayi
ortalama = toplam / len(liste)
return ortalama
# Test
notlar1 = [85, 90, 78, 92, 88]
notlar2 = [60, 70, 65, 80, 75]
print(f"Notlar 1: {notlar1}")
print(f"Ortalama: {ortalama_hesapla(notlar1):.2f}")
print()
print(f"Notlar 2: {notlar2}")
print(f"Ortalama: {ortalama_hesapla(notlar2):.2f}")
def linear_search(liste, aranan):
"""
Listedeki bir elemanı arar ve indeksini döndürür.
Bulunamazsa -1 döndürür.
"""
for i in range(len(liste)):
if liste[i] == aranan:
return i # Bulundu, indeksini döndür
return -1 # Bulunamadı
# Test
isimler = ["Ali", "Ayşe", "Mehmet", "Fatma", "Ahmet"]
sayilar = [10, 25, 30, 45, 50, 75]
print(f"İsimler: {isimler}")
print(f"'Mehmet' aranıyor...")
indeks = linear_search(isimler, "Mehmet")
if indeks != -1:
print(f"Bulundu! İndeks: {indeks}")
else:
print("Bulunamadı!")
print()
print(f"'Zeynep' aranıyor...")
indeks = linear_search(isimler, "Zeynep")
if indeks != -1:
print(f"Bulundu! İndeks: {indeks}")
else:
print("Bulunamadı!")
print()
print(f"Sayılar: {sayilar}")
print(f"45 aranıyor: İndeks = {linear_search(sayilar, 45)}")
print(f"100 aranıyor: İndeks = {linear_search(sayilar, 100)}")
def asal_mi(sayi):
"""
Bir sayının asal olup olmadığını kontrol eder
Return: True (asal) veya False (asal değil)
"""
if sayi < 2:
return False
if sayi == 2:
return True
if sayi % 2 == 0:
return False
# 3'ten başlayarak sayının kareköküne kadar kontrol et
for i in range(3, int(sayi**0.5) + 1, 2):
if sayi % i == 0:
return False
return True
def asal_sayilari_listele(baslangic, bitis):
"""Verilen aralıktaki asal sayıları listeler"""
asal_liste = []
for sayi in range(baslangic, bitis + 1):
if asal_mi(sayi):
asal_liste.append(sayi)
return asal_liste
# Test
print("Asal mı kontrolleri:")
test_sayilar = [2, 3, 4, 5, 10, 17, 19, 20, 23, 25]
for sayi in test_sayilar:
sonuc = "ASAL" if asal_mi(sayi) else "ASAL DEĞİL"
print(f"{sayi}: {sonuc}")
print("\n1-50 arası asal sayılar:")
asallar = asal_sayilari_listele(1, 50)
print(asallar)
print(f"Toplam {len(asallar)} adet asal sayı var")
def sayi_degistir(x):
"""Sayıyı değiştirmeye çalışır"""
print(f"Fonksiyon içinde (önce): x = {x}")
x = x + 10
print(f"Fonksiyon içinde (sonra): x = {x}")
return x
# Ana program
sayi = 5
print(f"Fonksiyon öncesi: sayi = {sayi}")
sonuc = sayi_degistir(sayi)
print(f"Fonksiyon sonrası: sayi = {sayi}")
print(f"Return değeri: sonuc = {sonuc}")
print("\nGöründüğü gibi, orijinal 'sayi' değişmedi!")
def liste_degistir(liste):
"""Listeyi değiştirir"""
print(f"Fonksiyon içinde (önce): {liste}")
liste.append(99)
liste[0] = 999
print(f"Fonksiyon içinde (sonra): {liste}")
# Ana program
sayilar = [1, 2, 3, 4, 5]
print(f"Fonksiyon öncesi: {sayilar}")
liste_degistir(sayilar)
print(f"Fonksiyon sonrası: {sayilar}")
print("\n⚠️ DİKKAT: Orijinal liste değişti!")
Bir fonksiyonun kendi kendini çağırmasına recursion denir.
Her recursive fonksiyonda iki kritik bölüm vardır:
Recursion'u gerçekten anlamak için debugger kullanın:
faktoriyel fonksiyonunun içine breakpoint koyunn değerinin nasıl değiştiğini izleyindef faktoriyel(n):
"""Recursive faktöriyel hesaplama"""
# Base case
if n == 0 or n == 1:
return 1
# Recursive case
return n * faktoriyel(n - 1)
# Test
print("Faktöriyel hesaplamaları:")
for i in range(1, 8):
print(f"{i}! = {faktoriyel(i)}")
def fibonacci(n):
"""
N. Fibonacci sayısını hesaplar
Fibonacci: 0, 1, 1, 2, 3, 5, 8, 13, 21, ...
"""
# Base cases
if n == 0:
return 0
if n == 1:
return 1
# Recursive case
return fibonacci(n - 1) + fibonacci(n - 2)
# İlk 10 Fibonacci sayısı
print("Fibonacci Serisi:")
for i in range(10):
print(f"F({i}) = {fibonacci(i)}")
⚠️ Dikkat: Aynı değerler tekrar tekrar hesaplanıyor! (Kırmızı ile işaretli)
fib(5) = fib(4) + fib(3) = 3 + 2 = 5 │ ├── fib(4) = fib(3) + fib(2) = 2 + 1 = 3 │ │ │ ├── fib(3) = fib(2) + fib(1) = 1 + 1 = 2 │ │ │ │ │ ├── fib(2) 🔄 = fib(1) + fib(0) = 1 + 0 = 1 │ │ │ ├── fib(1) = 1 ✅ BASE │ │ │ └── fib(0) = 0 ✅ BASE │ │ │ │ │ └── fib(1) = 1 ✅ BASE │ │ │ └── fib(2) 🔄 = fib(1) + fib(0) = 1 + 0 = 1 │ ├── fib(1) = 1 ✅ BASE │ └── fib(0) = 0 ✅ BASE │ └── fib(3) 🔄 = fib(2) + fib(1) = 1 + 1 = 2 │ ├── fib(2) 🔄 = fib(1) + fib(0) = 1 + 0 = 1 │ ├── fib(1) = 1 ✅ BASE │ └── fib(0) = 0 ✅ BASE │ └── fib(1) = 1 ✅ BASE
Bir fonksiyonun kendini çağırmasıdır. Her recursive fonksiyonun iki bileşeni olmalı:
| Özellik | 🔄 Recursion | 🔁 Iteration (Döngü) |
|---|---|---|
| Bellek | Her çağrı stack'te yer kaplar | Sabit bellek kullanımı |
| Hız | Fonksiyon çağrısı overhead'i var | Genellikle daha hızlı |
| Okunabilirlik | Bazı problemler için daha temiz | Basit problemler için daha açık |
| Limit | Stack overflow riski (Python: ~1000) | Pratik limit yok |
Fibonacci gibi tekrarlı hesaplamalarda memoization (sonuçları önbellekleme) kullanın:
from functools import lru_cache
@lru_cache(maxsize=None)
def fib_memo(n):
if n <= 1: return n
return fib_memo(n-1) + fib_memo(n-2)
# fib(50) artık milisaniyede hesaplanır!
Yeni başlayanlar için en zor sorulardan biri: "Bu kodu fonksiyon yapmalı mıyım?" İşte basit kurallar:
| 🔁 Kod tekrarı | Aynı veya benzer kodu 2+ kez yazdın |
| 📦 Mantıksal birim | Bir işlem grubu tek bir amaç için çalışıyor (örn: "dosya oku", "ortalama hesapla") |
| 📏 Uzun kod bloğu | 10-15 satırdan uzun bir iş yapılıyor |
| 🏷️ İsim verilebilir | Kod bloğuna anlamlı bir isim verebiliyorsun ("kullanici_dogrula", "rapor_olustur") |
| 📝 Tek satır + tek kullanım | print("Merhaba") gibi basit kodlar için fonksiyon gereksiz |
| 📦 Çok fazla parametre | 7-8 parametre alan fonksiyon muhtemelen yanlış tasarlanmış |
| ✨ Zaten çok basit | Gereksiz karmaşıklık ekleme, basit tutulabilecek kodu karmaşıklaştırma |
# Program boyunca 5 farklı yerde kullanıcı yaşını doğruluyorsun
# HER SEFERINDE aynı kontrol:
if yas < 0 or yas > 150:
print("Geçersiz yaş!")
else:
print("Yaş geçerli")
# ✅ ÇÖZÜM: Fonksiyon yap!
def yas_gecerli_mi(yas):
"""Yaşın geçerli aralıkta olup olmadığını kontrol eder"""
return 0 <= yas <= 150
# Artık her yerde:
if yas_gecerli_mi(yas):
# devam et...
# Sadece bir kez kullanılacak basit bir print
print("Program başlıyor...")
# ❌ BU GEREKSIZ:
def baslangic_mesaji():
print("Program başlıyor...")
baslangic_mesaji()
# Tek satırlık, tek kullanımlık kod için fonksiyon fazla!
— Unix Felsefesi / Clean Code Prensibi