Python [4] : Python Fonksiyonları; Kodunuzu Organize Etme ve Yeniden Kullanma Sanatı

Modern programlamanın temel yapı taşlarından biri olan fonksiyonlar, belirli bir görevi yerine getiren, yeniden kullanılabilir kod bloklarıdır. Python’da fonksiyonlar, kodumuzu daha modüler, organize, okunabilir ve bakımı kolay hale getirmenin anahtarıdır. Tekrarlayan kod parçalarını bir fonksiyon altında toplayarak, aynı işlevi programın farklı yerlerinde tekrar tekrar yazmak yerine sadece fonksiyonu çağırarak gerçekleştirebiliriz. Bu kapsamlı rehberde, Python’daki fonksiyon kavramını derinlemesine inceleyeceğiz. Fonksiyonların nasıl tanımlandığını (def anahtar kelimesi), nasıl çağrıldığını, dışarıdan nasıl veri aldığını (argümanlar/parametreler), nasıl sonuç döndürdüğünü (return ifadesi) ve daha gelişmiş konular olan değişken sayıda argüman almayı (*args ve **kwargs) ayrıntılı örneklerle ele alacağız. Fonksiyonları etkili bir şekilde kullanmak, Python’da ustalaşmanın önemli bir adımıdır ve daha büyük, daha karmaşık projeler geliştirmenize olanak tanır. Bölüm 1: Fonksiyon Nedir ve Neden Kullanılır? En basit tanımıyla bir fonksiyon, belirli bir işi yapmak üzere tasarlanmış, isimlendirilmiş bir kod bloğudur. Matematikteki fonksiyonlara benzer şekilde, girdi (argüman) alabilir, bu girdiler üzerinde işlemler yapabilir ve bir çıktı (dönüş değeri) üretebilirler (ancak girdi almak veya çıktı üretmek zorunlu değildir). Fonksiyon kullanmanın temel avantajları şunlardır: Modülerlik: Karmaşık bir problemi daha küçük, yönetilebilir alt görevlere ayırmamızı sağlar. Her fonksiyon belirli bir alt görevi yerine getirir. Yeniden Kullanılabilirlik (Reusability): Aynı kod bloğunu programın farklı yerlerinde tekrar tekrar yazmak yerine, fonksiyonu tanımlayıp ihtiyaç duyulan her yerde çağırabiliriz. Bu, kod tekrarını (DRY — Don’t Repeat Yourself prensibi) önler. Okunabilirlik: İyi isimlendirilmiş fonksiyonlar, kodun ne yaptığını anlamayı kolaylaştırır. Karmaşık bir işlem tek bir fonksiyon çağrısıyla ifade edilebilir. Bakım Kolaylığı: Bir işlevde değişiklik yapılması gerektiğinde, sadece ilgili fonksiyonun içini değiştirmek yeterlidir. Bu değişiklik, fonksiyonun çağrıldığı her yere otomatik olarak yansır. Soyutlama (Abstraction): Fonksiyonu kullanan kişinin, fonksiyonun iç detaylarını (nasıl çalıştığını) bilmesine gerek yoktur; sadece ne iş yaptığını ve nasıl kullanılacağını bilmesi yeterlidir. Bölüm 2: Fonksiyon Tanımlama (def) ve Çağırma 2.1. Fonksiyon Tanımlama Python’da bir fonksiyon tanımlamak için def anahtar kelimesi kullanılır. Temel sözdizimi şöyledir: def fonksiyon_adı(parametre1, parametre2, ...): """ Bu kısım Docstring olarak adlandırılır. (İsteğe bağlı ama şiddetle tavsiye edilir) Fonksiyonun ne yaptığını, parametrelerini ve varsa dönüş değerini açıklar. """ # Fonksiyonun gövdesi (girintili kod bloğu) # Burada işlemler yapılır # ... # İsteğe bağlı olarak bir değer döndürülebilir return dönüş_değeri Sözdiziminin bileşenleri: def: Fonksiyon tanımını başlatan anahtar kelime. fonksiyon_adı: Fonksiyona verdiğimiz isim. Python isimlendirme kurallarına uymalıdır (harf veya alt çizgi ile başlamalı, harf, rakam, alt çizgi içerebilir, küçük harf ve kelimeler arası alt çizgi (snake_case) PEP 8 standardıdır). (parametre1, parametre2, ...): Fonksiyonun dışarıdan alacağı girdileri temsil eden değişkenler (parametreler). Parantezler zorunludur, parametre olmasa bile boş parantez () kullanılır. Parametreler virgülle ayrılır. : (İki Nokta Üst Üste): Fonksiyon başlığını sonlandırır ve fonksiyon gövdesinin başlayacağını belirtir. Docstring (Belgelendirme Metni): Üçlü tırnak ("""...""" veya '''...''') içinde yazılan ve fonksiyonun amacını, parametrelerini vb. açıklayan metin. Fonksiyonun ilk ifadesi olmalıdır. Zorunlu değildir ancak iyi bir programlama pratiğidir. Fonksiyon Gövdesi: Fonksiyonun çalıştıracağı kodları içeren, girintili blok. Tüm gövde aynı seviyede girintili olmalıdır. return dönüş_değeri: Fonksiyondan bir değer döndürmek için kullanılır (isteğe bağlı). Bu konuya daha sonra detaylı değineceğiz. Basit Bir Örnek: Basit bir selamlama fonksiyonu tanımlama def selamla(): """Basit bir selamlama mesajı yazdırır.""" print("Merhaba!") print("Python Fonksiyonları Dünyasına Hoş Geldiniz!") Başka bir örnek: İki sayıyı toplayan fonksiyon def topla(sayi1, sayi2): """Verilen iki sayıyı toplar ve sonucu yazdırır.""" sonuc = sayi1 + sayi2 print(f"{sayi1} + {sayi2} = {sonuc}") 2.2. Fonksiyon Çağırma (Calling a Function) Bir fonksiyonu tanımlamak, onun çalışacağı anlamına gelmez. Fonksiyonun kodunu çalıştırmak için onu çağırmamız gerekir. Fonksiyon çağırma, fonksiyonun adını yazıp yanına parantez () koyarak yapılır. Eğer fonksiyon parametre alıyorsa, parantez içine bu parametrelere karşılık gelen değerler (argümanlar) yazılır. Yukarıda tanımlanan fonksiyonları çağırma print("İlk fonksiyon çağrılıyor...") selamla() # selamla fonksiyonunu çalıştırır print("İlk fonksiyon bitti.") print("\nİkinci fonksiyon çağrılıyor...") topla(15, 7) # topl

Apr 9, 2025 - 12:01
 0
Python [4] : Python Fonksiyonları; Kodunuzu Organize Etme ve Yeniden Kullanma Sanatı

Modern programlamanın temel yapı taşlarından biri olan fonksiyonlar, belirli bir görevi yerine getiren, yeniden kullanılabilir kod bloklarıdır. Python’da fonksiyonlar, kodumuzu daha modüler, organize, okunabilir ve bakımı kolay hale getirmenin anahtarıdır. Tekrarlayan kod parçalarını bir fonksiyon altında toplayarak, aynı işlevi programın farklı yerlerinde tekrar tekrar yazmak yerine sadece fonksiyonu çağırarak gerçekleştirebiliriz.

Bu kapsamlı rehberde, Python’daki fonksiyon kavramını derinlemesine inceleyeceğiz. Fonksiyonların nasıl tanımlandığını (def anahtar kelimesi), nasıl çağrıldığını, dışarıdan nasıl veri aldığını (argümanlar/parametreler), nasıl sonuç döndürdüğünü (return ifadesi) ve daha gelişmiş konular olan değişken sayıda argüman almayı (*args ve **kwargs) ayrıntılı örneklerle ele alacağız.

Fonksiyonları etkili bir şekilde kullanmak, Python’da ustalaşmanın önemli bir adımıdır ve daha büyük, daha karmaşık projeler geliştirmenize olanak tanır.

Bölüm 1: Fonksiyon Nedir ve Neden Kullanılır?
En basit tanımıyla bir fonksiyon, belirli bir işi yapmak üzere tasarlanmış, isimlendirilmiş bir kod bloğudur. Matematikteki fonksiyonlara benzer şekilde, girdi (argüman) alabilir, bu girdiler üzerinde işlemler yapabilir ve bir çıktı (dönüş değeri) üretebilirler (ancak girdi almak veya çıktı üretmek zorunlu değildir).

Fonksiyon kullanmanın temel avantajları şunlardır:

Modülerlik: Karmaşık bir problemi daha küçük, yönetilebilir alt görevlere ayırmamızı sağlar. Her fonksiyon belirli bir alt görevi yerine getirir.
Yeniden Kullanılabilirlik (Reusability): Aynı kod bloğunu programın farklı yerlerinde tekrar tekrar yazmak yerine, fonksiyonu tanımlayıp ihtiyaç duyulan her yerde çağırabiliriz. Bu, kod tekrarını (DRY — Don’t Repeat Yourself prensibi) önler.
Okunabilirlik: İyi isimlendirilmiş fonksiyonlar, kodun ne yaptığını anlamayı kolaylaştırır. Karmaşık bir işlem tek bir fonksiyon çağrısıyla ifade edilebilir.
Bakım Kolaylığı: Bir işlevde değişiklik yapılması gerektiğinde, sadece ilgili fonksiyonun içini değiştirmek yeterlidir. Bu değişiklik, fonksiyonun çağrıldığı her yere otomatik olarak yansır.
Soyutlama (Abstraction): Fonksiyonu kullanan kişinin, fonksiyonun iç detaylarını (nasıl çalıştığını) bilmesine gerek yoktur; sadece ne iş yaptığını ve nasıl kullanılacağını bilmesi yeterlidir.
Bölüm 2: Fonksiyon Tanımlama (def) ve Çağırma
2.1. Fonksiyon Tanımlama
Python’da bir fonksiyon tanımlamak için def anahtar kelimesi kullanılır. Temel sözdizimi şöyledir:

def fonksiyon_adı(parametre1, parametre2, ...):
"""
Bu kısım Docstring olarak adlandırılır. (İsteğe bağlı ama şiddetle tavsiye edilir)
Fonksiyonun ne yaptığını, parametrelerini ve varsa dönüş değerini açıklar.
"""
# Fonksiyonun gövdesi (girintili kod bloğu)
# Burada işlemler yapılır
# ...
# İsteğe bağlı olarak bir değer döndürülebilir
return dönüş_değeri
Sözdiziminin bileşenleri:

def: Fonksiyon tanımını başlatan anahtar kelime.
fonksiyon_adı: Fonksiyona verdiğimiz isim. Python isimlendirme kurallarına uymalıdır (harf veya alt çizgi ile başlamalı, harf, rakam, alt çizgi içerebilir, küçük harf ve kelimeler arası alt çizgi (snake_case) PEP 8 standardıdır).
(parametre1, parametre2, ...): Fonksiyonun dışarıdan alacağı girdileri temsil eden değişkenler (parametreler). Parantezler zorunludur, parametre olmasa bile boş parantez () kullanılır. Parametreler virgülle ayrılır.
: (İki Nokta Üst Üste): Fonksiyon başlığını sonlandırır ve fonksiyon gövdesinin başlayacağını belirtir.
Docstring (Belgelendirme Metni): Üçlü tırnak ("""...""" veya '''...''') içinde yazılan ve fonksiyonun amacını, parametrelerini vb. açıklayan metin. Fonksiyonun ilk ifadesi olmalıdır. Zorunlu değildir ancak iyi bir programlama pratiğidir.
Fonksiyon Gövdesi: Fonksiyonun çalıştıracağı kodları içeren, girintili blok. Tüm gövde aynı seviyede girintili olmalıdır.
return dönüş_değeri: Fonksiyondan bir değer döndürmek için kullanılır (isteğe bağlı). Bu konuya daha sonra detaylı değineceğiz.
Basit Bir Örnek:

Basit bir selamlama fonksiyonu tanımlama

def selamla():
"""Basit bir selamlama mesajı yazdırır."""
print("Merhaba!")
print("Python Fonksiyonları Dünyasına Hoş Geldiniz!")

Başka bir örnek: İki sayıyı toplayan fonksiyon

def topla(sayi1, sayi2):
"""Verilen iki sayıyı toplar ve sonucu yazdırır."""
sonuc = sayi1 + sayi2
print(f"{sayi1} + {sayi2} = {sonuc}")
2.2. Fonksiyon Çağırma (Calling a Function)
Bir fonksiyonu tanımlamak, onun çalışacağı anlamına gelmez. Fonksiyonun kodunu çalıştırmak için onu çağırmamız gerekir. Fonksiyon çağırma, fonksiyonun adını yazıp yanına parantez () koyarak yapılır. Eğer fonksiyon parametre alıyorsa, parantez içine bu parametrelere karşılık gelen değerler (argümanlar) yazılır.

Yukarıda tanımlanan fonksiyonları çağırma

print("İlk fonksiyon çağrılıyor...")
selamla() # selamla fonksiyonunu çalıştırır
print("İlk fonksiyon bitti.")
print("\nİkinci fonksiyon çağrılıyor...")
topla(15, 7) # topla fonksiyonunu 15 ve 7 argümanlarıyla çalıştırır
topla(-5, 12) # Farklı argümanlarla tekrar çağırabiliriz
print("İkinci fonksiyon bitti.")

Fonksiyonu bir değişkene atayamazsınız (doğrudan çalıştırmadan)

x = topla # Bu, fonksiyonun kendisini x'e atar, çalıştırmaz

x(10, 20) # Şimdi çağırabilirsiniz

Çağırırken parametre sayısına dikkat edilmelidir:

topla(10) # Hata verir: TypeError: topla() missing 1 required positional argument: 'sayi2'

topla(1, 2, 3) # Hata verir: TypeError: topla() takes 2 positional arguments but 3 were given

Bölüm 3: Docstrings (Belgelendirme Metinleri)
Daha önce bahsettiğimiz gibi, def satırından hemen sonra gelen üçlü tırnak içindeki metin docstring olarak adlandırılır. Docstring’ler, fonksiyonun ne yaptığını, hangi parametreleri aldığını, bu parametrelerin ne anlama geldiğini ve fonksiyonun ne döndürdüğünü açıklamak için kullanılır.

Neden önemlidirler?

Belgelendirme: Kodun anlaşılmasına yardımcı olurlar. Hem kodu yazan kişi için hem de kodu okuyan başkaları için bir kılavuz görevi görürler.
Yardımcı Araçlar: Python’un yerleşik help() fonksiyonu ve birçok IDE (Tümleşik Geliştirme Ortamı), bir fonksiyonun docstring'ini otomatik olarak göstererek kullanımı kolaylaştırır.
Otomatik Belge Üretimi: Sphinx gibi araçlar, kod içindeki docstring’leri kullanarak otomatik olarak proje belgeleri oluşturabilir.
İyi bir docstring genellikle şu bilgileri içerir (PEP 257 standardına göre):

Fonksiyonun ne yaptığına dair kısa bir özet (ilk satır).
(Gerekirse) Daha ayrıntılı bir açıklama (bir boş satırdan sonra).
Parametrelerin açıklaması (Args: veya Parameters: başlığı altında).
Dönüş değerinin açıklaması (Returns: başlığı altında).
Fonksiyonun tetikleyebileceği istisnalar (Raises: başlığı altında, isteğe bağlı).
import math
def daire_alani(yaricap):
"""
Verilen yarıçapa sahip bir dairenin alanını hesaplar.
Args:
yaricap (float veya int): Dairenin yarıçapı (negatif olmamalı).
Returns:
float: Dairenin hesaplanan alanı.
None: Eğer yarıçap negatifse None döndürür ve bir uyarı yazdırır.
Raises:
TypeError: Eğer yarıçap sayısal bir değer değilse.
"""
if not isinstance(yaricap, (int, float)):
raise TypeError("Yarıçap sayısal bir değer olmalıdır.")
if yaricap < 0:
print("Uyarı: Yarıçap negatif olamaz.")
return None # Negatif yarıçap için None döndür
alan = math.pi * (yaricap ** 2)
return alan

Docstring'e erişim

print(daire_alani.doc)

help() fonksiyonu ile docstring'i görme

help(daire_alani) # Bu satırı Python interaktif kabuğunda veya script'te çalıştırabilirsiniz

Bölüm 4: return İfadesi: Fonksiyondan Değer Döndürme
Birçok fonksiyonun temel amacı, bir hesaplama yapmak veya bir işlem gerçekleştirmek ve sonucunu fonksiyonu çağıran yere geri göndermektir. Bu işlem return ifadesi ile yapılır.

return ifadesine ulaşıldığında, fonksiyonun çalışması anında durur ve belirtilen değer fonksiyonun çağrıldığı yere gönderilir.
return ifadesinden sonra yazılan kodlar çalıştırılmaz.
Bir fonksiyon birden fazla return ifadesi içerebilir (örneğin farklı if bloklarında), ancak fonksiyon çalıştığında bunlardan sadece bir tanesi yürütülür.
Eğer bir fonksiyon return ifadesi içermiyorsa veya return ifadesinden sonra bir değer belirtilmemişse (return tek başına kullanılmışsa), fonksiyon varsayılan olarak özel bir değer olan None'u döndürür. None Python'da "hiçbir değer yok" anlamına gelir.

Değer döndüren bir fonksiyon

def carp(a, b):
"""İki sayıyı çarpar ve sonucu döndürür."""
sonuc = a * b
return sonuc
print("Bu satır asla çalışmaz çünkü return'den sonra.")

Fonksiyonu çağırıp dönüş değerini bir değişkene atama

carpim_sonucu = carp(6, 7)
print(f"Çarpım sonucu: {carpim_sonucu}") # Çarpım sonucu: 42
print(f"Başka bir çarpım: {carp(10, -2)}") # Başka bir çarpım: -20

Return kullanmayan (veya değeri olmayan) fonksiyon None döndürür

def mesaj_yazdir(mesaj):
"""Verilen mesajı ekrana yazdırır."""
print(mesaj)
# return ifadesi yok
donen_deger = mesaj_yazdir("Bu bir test mesajıdır.")
print(f"mesaj_yazdir fonksiyonundan dönen değer: {donen_deger}") # None

Boş return de None döndürür

def bos_return_fonksiyonu(x):
"""x 5'ten büyükse True, değilse None döndürür."""
if x > 5:
return True
return # Burada return None ile aynı işlevi görür
print(f"bos_return_fonksiyonu(10): {bos_return_fonksiyonu(10)}") # True
print(f"bos_return_fonksiyonu(3): {bos_return_fonksiyonu(3)}") # None
Birden Fazla Değer Döndürme
Python’da bir fonksiyon teknik olarak sadece tek bir nesne döndürebilir. Ancak, birden fazla değeri tek bir return ifadesiyle döndürmek istediğimizde, Python bu değerleri otomatik olarak bir tuple (demet) içine paketler.

def dikdortgen_hesapla(genislik, yukseklik):
"""Dikdörtgenin alanını ve çevresini hesaplar."""
alan = genislik * yukseklik
cevre = 2 * (genislik + yukseklik)
return alan, cevre # İki değer virgülle ayrılmış, tuple olarak dönecek
hesap_sonuclari = dikdortgen_hesapla(10, 5)
print(f"Dönen değer: {hesap_sonuclari}") # Dönen değer: (50, 30) - bir tuple
print(f"Dönen değerin tipi: {type(hesap_sonuclari)}") #

Dönen tuple'ı doğrudan değişkenlere atayabiliriz (tuple unpacking)

alan_degeri, cevre_degeri = dikdortgen_hesapla(8, 6)
print(f"Alan: {alan_degeri}") # Alan: 48
print(f"Çevre: {cevre_degeri}") # Çevre: 28
Bölüm 5: Parametreler ve Argümanlar
Fonksiyon tanımlarken ve çağırırken kullanılan terimler bazen karıştırılabilir:

Parametre (Parameter): Fonksiyon tanımında, parantez içinde yer alan değişken isimleridir. Fonksiyonun kabul edeceği girdiler için yer tutuculardır (örneğin, def topla(sayi1, sayi2): ifadesindeki sayi1 ve sayi2).
Argüman (Argument): Fonksiyon çağrılırken, parantez içine yazılan gerçek değerlerdir. Bu değerler, fonksiyon içindeki karşılık gelen parametrelere atanır (örneğin, topla(15, 7) çağrısındaki 15 ve 7).
Yani, parametreler fonksiyonun “beklediği” şeylerdir, argümanlar ise fonksiyon çağrıldığında “verilen” gerçek değerlerdir.

Bölüm 6: Argüman Türleri
Python, fonksiyonlara argüman geçirmenin çeşitli yollarını sunar. Bu esneklik, fonksiyonları daha kullanışlı hale getirir.

6.1. Konumsal Argümanlar (Positional Arguments)
Bunlar en temel argüman türüdür. Fonksiyon çağrılırken verilen argümanlar, fonksiyon tanımındaki parametrelerle sırasına göre eşleştirilir.

def tanitim(ad, sehir, meslek):
"""Kişisel bilgileri yazdırır."""
print(f"Ad: {ad}")
print(f"Şehir: {sehir}")
print(f"Meslek: {meslek}")

Konumsal argümanlarla çağırma

tanitim("Ayşe", "İstanbul", "Mühendis")

"Ayşe" -> ad parametresine

"İstanbul" -> sehir parametresine

"Mühendis" -> meslek parametresine atanır.

Sıra önemlidir! Yanlış sıra hatalı eşleşmeye yol açar:

print("\nYanlış sıra ile çağırma:")
tanitim("Doktor", "Ali", "Ankara")

"Doktor" -> ad

"Ali" -> sehir

"Ankara" -> meslek (Mantıksal olarak yanlış!)

6.2. Anahtar Kelime Argümanları (Keyword Arguments)
Fonksiyonu çağırırken, argümanları parametre_adı=değer şeklinde belirterek geçirebiliriz. Bu yöntemde argümanların sırası önemli değildir, çünkü Python hangi argümanın hangi parametreye ait olduğunu isim eşleşmesiyle anlar. Bu, özellikle çok sayıda parametresi olan fonksiyonlarda okunabilirliği artırır.

Anahtar kelime argümanlarıyla çağırma (tanitim fonksiyonu yukarıdakiyle aynı)

print("\nAnahtar kelime argümanları ile çağırma:")
tanitim(ad="Mehmet", meslek="Öğretmen", sehir="İzmir") # Sıra farklı ama doğru eşleşir
tanitim(sehir="Bursa", ad="Fatma", meslek="Avukat") # Farklı sıra, yine doğru eşleşir
Konumsal ve Anahtar Kelime Argümanlarını Karıştırma
Bir fonksiyon çağrısında hem konumsal hem de anahtar kelime argümanları kullanılabilir. Ancak önemli bir kural vardır: Tüm konumsal argümanlar, tüm anahtar kelime argümanlarından önce gelmelidir.

Konumsal ve anahtar kelime argümanlarını karıştırma

tanitim("Zeynep", meslek="Grafiker", sehir="Adana") # Doğru: Önce konumsal ("Zeynep"), sonra anahtar kelime

tanitim(ad="Kemal", "Antalya", meslek="Mimar") # Hata! Positional argument follows keyword argument

Yukarıdaki satır çalıştırılırsa SyntaxError alınır.

6.3. Varsayılan Argüman Değerleri (Default Argument Values)
Fonksiyon tanımında parametrelere varsayılan değerler atayabiliriz. Eğer fonksiyon çağrılırken bu parametre için bir argüman verilmezse, tanımlanan varsayılan değer kullanılır. Bu, bazı parametreleri isteğe bağlı hale getirir.

Kural: Varsayılan değere sahip parametreler, fonksiyon tanımında varsayılan değeri olmayan parametrelerden sonra gelmelidir.

def us_al(taban, us=2): # 'us' parametresinin varsayılan değeri 2
"""Verilen tabanın belirtilen üssünü (varsayılan olarak karesini) hesaplar."""
return taban ** us

Varsayılan üs (2) ile çağırma

print(f"5'in karesi: {us_al(5)}") # 5'in karesi: 25

Farklı bir üs belirterek çağırma

print(f"3'ün 4. kuvveti: {us_al(3, 4)}") # 3'ün 4. kuvveti: 81

Anahtar kelime argümanı ile de kullanılabilir

print(f"2'nin 5. kuvveti: {us_al(taban=2, us=5)}") # 2'nin 5. kuvveti: 32
print(f"10'un karesi: {us_al(taban=10)}") # 10'un karesi: 100

def hatali_tanim(a=1, b): # Hata! non-default argument follows default argument

pass

Dikkat: Değiştirilebilir Varsayılan Argümanlar! Varsayılan argüman değeri olarak liste [] veya sözlük {} gibi değiştirilebilir (mutable) nesneler kullanmaktan kaçının. Çünkü varsayılan değerler fonksiyon tanımlandığında sadece bir kez oluşturulur. Fonksiyon her çağrıldığında aynı liste veya sözlük nesnesi tekrar kullanılır ve üzerinde yapılan değişiklikler sonraki çağrıları etkiler. Bu genellikle istenmeyen bir durumdur.

Yanlış kullanım (Mutable default)

def listeye_ekle_hatali(eleman, liste=[]):
liste.append(eleman)
return liste
print(listeye_ekle_hatali(1)) # [1]
print(listeye_ekle_hatali(2)) # 1, 2
print(listeye_ekle_hatali(3)) # [1, 2, 3]

Doğru kullanım (None ve kontrol)

def listeye_ekle_dogru(eleman, liste=None):
if liste is None:
liste = [] # Liste None ise her çağrıda yeni boş liste oluştur
liste.append(eleman)
return liste
print(listeye_ekle_dogru(1)) # [1]
print(listeye_ekle_dogru(2)) # 2
liste_a = [10]
print(listeye_ekle_dogru(3, liste_a)) # 10, 3
print(listeye_ekle_dogru(4)) # [4]
Bölüm 7: Değişken Sayıda Argüman Alma (*args ve **kwargs)
Bazen bir fonksiyonun kaç tane argüman alacağını önceden bilemeyebiliriz. Python, bu durumlar için iki özel sözdizimi sunar: *args ve **kwargs.

7.1. *args (Arbitrary Positional Arguments - İsteğe Bağlı Konumsal Argümanlar)
Fonksiyon tanımında bir parametre adının başına tek bir yıldız * koyarsak (geleneksel olarak *args ismi kullanılır, ancak zorunlu değildir, *sayilar gibi başka bir isim de olabilir), bu parametre, fonksiyona verilen tüm eşleşmeyen konumsal argümanları bir tuple (demet) içinde toplar.

Bu, fonksiyona istediğiniz sayıda konumsal argüman göndermenizi sağlar.

def sayilari_topla(*args):
"""Verilen tüm sayıları toplar."""
print(f"Gelen argümanlar (args): {args}") # args bir tuple'dır
print(f"Argümanların tipi: {type(args)}")
toplam = 0
for sayi in args:
toplam += sayi
return toplam
print(sayilari_topla(1, 2, 3)) # Gelen argümanlar (args): (1, 2, 3) -> Sonuç: 6
print(sayilari_topla(10, 20, 30, 40, 50)) # Gelen argümanlar (args): (10, 20, 30, 40, 50) -> Sonuç: 150
print(sayilari_topla()) # Gelen argümanlar (args): () -> Sonuç: 0

Normal parametrelerle birlikte kullanımı

def bilgileri_yazdir(zorunlu_bilgi, ekstra_bilgiler):
"""Zorunlu bilgiyi ve ardından gelen ekstra bilgileri yazdırır."""
print(f"Zorunlu Bilgi: {zorunlu_bilgi}")
if ekstra_bilgiler: # Eğer ekstra_bilgiler tuple'ı boş değilse
print("Ekstra Bilgiler:")
for i, bilgi in enumerate(ekstra_bilgiler):
print(f"- {i+1}: {bilgi}")
else:
print("Ekstra bilgi yok.")
bilgileri_yazdir("Önemli Duyuru", "Detay 1", "Detay 2", "Son Not")
print("-" * 20)
bilgileri_yazdir("Başka Bir Duyuru")
7.2. **kwargs (Arbitrary Keyword Arguments - İsteğe Bağlı Anahtar Kelime Argümanları)
Fonksiyon tanımında bir parametre adının başına çift yıldız *
koyarsak (geleneksel olarak **kwargs ismi kullanılır), bu parametre, fonksiyona verilen tüm eşleşmeyen anahtar kelime argümanlarını bir sözlük (dictionary) içinde toplar. Anahtarlar argüman isimleri (string), değerler ise argüman değerleridir.

Bu, fonksiyona istediğiniz sayıda ve isimde anahtar kelime argümanı göndermenizi sağlar.

def kullanici_profili(**kwargs):
"""Kullanıcı profil bilgilerini anahtar-değer olarak yazdırır."""
print(f"Gelen anahtar kelime argümanları (kwargs): {kwargs}")
print(f"kwargs'ın tipi: {type(kwargs)}")
if not kwargs:
print("Profil bilgisi girilmedi.")
return
print("\nKullanıcı Profili:")
for anahtar, deger in kwargs.items():
print(f"- {anahtar.capitalize()}: {deger}")
kullanici_profili(ad="Ali", soyad="Yılmaz", yas=30, sehir="Ankara")
print("-" * 20)
kullanici_profili(urun_adi="Laptop", marka="XYZ", fiyat=15000, stok=50)
print("-" * 20)
kullanici_profili()

Normal parametreler, *args ve **kwargs birlikte kullanımı

def kapsamli_fonksiyon(param1, param2=10, *args, **kwargs):
"""Tüm argüman tiplerini gösteren bir fonksiyon."""
print(f"param1 (Zorunlu Konumsal): {param1}")
print(f"param2 (Varsayılan Değerli): {param2}")
print(f"args (Ekstra Konumsal): {args}")
print(f"kwargs (Ekstra Anahtar Kelime): {kwargs}")
print("\nKapsamlı Fonksiyon Çağrısı 1:")
kapsamli_fonksiyon(1, 2, 3, 4, 5, isim="Can", yas=25)

param1: 1

param2: 2 (varsayılan ezildi)

args: (3, 4, 5)

kwargs: {'isim': 'Can', 'yas': 25}

print("\nKapsamlı Fonksiyon Çağrısı 2:")
kapsamli_fonksiyon("Merhaba", renk="Mavi", boyut="XL")

param1: "Merhaba"

param2: 10 (varsayılan kullanıldı)

args: () (Boş tuple)

kwargs: {'renk': 'Mavi', 'boyut': 'XL'}

Bölüm 8: Parametre Sıralama Kuralları
Bir fonksiyon tanımında farklı türdeki parametreleri bir arada kullanırken Python’un zorunlu kıldığı bir sıra vardır:

Standart Konumsal veya Anahtar Kelime Argümanları: (Örn: a, b)
Varsayılan Değerli Argümanlar: (Örn: c=10, d='test')
*args: (İsteğe bağlı konumsal argümanları toplar)
Anahtar Kelime-Sadece Argümanlar (Keyword-Only Arguments): (*args'dan veya tek başına *'dan sonra gelen ve varsayılan değeri olabilen argümanlar. Bunlar sadece anahtar kelime ile çağrılabilir.)
**kwargs: (İsteğe bağlı anahtar kelime argümanlarını toplar - her zaman en sonda olmalıdır)
Ayrıca, Python 3.8 ile gelen Konum-Sadece Argümanlar (Positional-Only Arguments) da vardır. Bunlar, fonksiyon tanımında / (slash) karakterinden önce belirtilir ve sadece konumlarıyla çağrılabilirler, anahtar kelime argümanı olarak kullanılamazlar.

Tüm parametre türlerini gösteren (biraz karmaşık) bir örnek:

def cok_ozellikli_fonksiyon(pos_only1, pos_only2, /, std_pos_or_kw, , kw_only1, kw_only2="default", **kwargs):
"""
Python 3.8+ özelliklerini de içeren parametre sıralamasını gösterir.
pos_only1, pos_only2: Sadece konumsal olarak verilebilir.
std_pos_or_kw: Konumsal veya anahtar kelime olarak verilebilir.
kw_only1, kw_only2: Sadece anahtar kelime olarak verilebilir (
sonrası).
kwargs: Kalan tüm anahtar kelime argümanlarını toplar.
"""
print(f"pos_only1: {pos_only1}")
print(f"pos_only2: {pos_only2}")
print(f"std_pos_or_kw: {std_pos_or_kw}")
print(f"kw_only1: {kw_only1}")
print(f"kw_only2: {kw_only2}")
print(f"kwargs: {kwargs}")

Doğru Çağrı Örnekleri

print("Çağrı 1:")
cok_ozellikli_fonksiyon(1, 2, 3, kw_only1="a", kw_only2="b", extra="c")

Çıktı:

pos_only1: 1

pos_only2: 2

std_pos_or_kw: 3

kw_only1: a

kw_only2: b

kwargs: {'extra': 'c'}

print("\nÇağrı 2:")
cok_ozellikli_fonksiyon(10, 20, std_pos_or_kw=30, kw_only1="test")

Çıktı:

pos_only1: 10

pos_only2: 20

std_pos_or_kw: 30

kw_only1: test

kw_only2: default (varsayılan kullanıldı)

kwargs: {}

Hatalı Çağrı Örnekleri

cok_ozellikli_fonksiyon(pos_only1=1, pos_only2=2, ...) # Hata! Positional-only argümanlar anahtar kelimeyle verilemez.

cok_ozellikli_fonksiyon(1, 2, 3, "a", ...) # Hata! kw_only1 sadece anahtar kelimeyle verilmeli.

args ve **kwargs isimleri sadece bir konvansiyondur. Fonksiyon tanımında *pos_args veya **key_args gibi farklı isimler de kullanabilirsiniz, ancak genel kabul görmüş standart *args ve **kwargs'tır. Önemli olan başlarındaki * ve * sembolleridir.

Bölüm 9: Değişken Kapsamı (Scope)
Bir değişkenin programın hangi bölümünden erişilebilir olduğunu belirleyen kurallara kapsam (scope) denir. Python’da temel olarak iki ana kapsam bulunur: yerel (local) ve küresel (global).

9.1. Yerel Kapsam (Local Scope)
Bir fonksiyon içinde tanımlanan değişkenler yerel (local) kapsama sahiptir. Bu değişkenler sadece tanımlandıkları fonksiyonun içinden erişilebilir ve fonksiyonun çalışması bittiğinde genellikle bellekten silinirler.

def benim_fonksiyon():
fonksiyon_degiskeni = "Bu yerel bir değişkendir."
print(f"Fonksiyon içinden: {fonksiyon_degiskeni}")
benim_fonksiyon()

print(fonksiyon_degiskeni) # Hata! NameError: name 'fonksiyon_degiskeni' is not defined

Fonksiyon dışından yerel değişkene erişilemez.

9.2. Küresel Kapsam (Global Scope)
Fonksiyonların dışında, programın ana düzeyinde tanımlanan değişkenler küresel (global) kapsama sahiptir. Bu değişkenlere programın herhangi bir yerinden (fonksiyon içleri dahil) erişilebilir.

global_degisken = "Bu küresel bir değişkendir."
def baska_fonksiyon():
print(f"Fonksiyon içinden global değişken: {global_degisken}") # Erişim mümkün
baska_fonksiyon()
print(f"Fonksiyon dışından global değişken: {global_degisken}")
9.3. global Anahtar Kelimesi
Normalde, bir fonksiyon içinde küresel bir değişkene sadece okuma amaçlı erişebilirsiniz. Eğer fonksiyon içinde küresel bir değişkenin değerini değiştirmek isterseniz, Python o isimde yeni bir yerel değişken oluşturur ve küresel değişken etkilenmez.

Eğer fonksiyon içinde gerçekten küresel bir değişkeni değiştirmek istiyorsanız, o değişkeni fonksiyonun başında global anahtar kelimesi ile bildirmeniz gerekir.

sayac = 0 # Küresel sayaç
def sayaci_arttir_yanlis():
# global demediğimiz için Python burada yeni bir 'sayac' yerel değişkeni oluşturur
# sayac = sayac + 1 # Hata! UnboundLocalError: local variable 'sayac' referenced before assignment
# Yukarıdaki satır hata verir çünkü sağdaki 'sayac'ı okumaya çalışırken
# henüz yerel 'sayac'a değer atanmamıştır.
# Doğrusu şöyle olmalıydı (ama hala yerel):
yerel_sayac = sayac + 1 # Küresel sayacı okur, yerel değişkene atar
print(f"Yanlış fonksiyon içindeki (yerel) sayaç: {yerel_sayac}")
def sayaci_arttir_dogru():
global sayac # 'sayac' değişkeninin küresel olduğunu belirtiyoruz
sayac = sayac + 1
print(f"Doğru fonksiyon içindeki (küresel) sayaç: {sayac}")
print(f"Başlangıçtaki küresel sayaç: {sayac}") # 0

sayaci_arttir_yanlis() # Hata verir veya küreseli değiştirmez

sayaci_arttir_dogru() # Küresel sayacı değiştirir
print(f"Sonraki küresel sayaç: {sayac}") # 1
sayaci_arttir_dogru() # Küresel sayacı tekrar değiştirir
print(f"En son küresel sayaç: {sayac}") # 2
global anahtar kelimesini kullanmak genellikle önerilmez çünkü kodun takibini zorlaştırabilir ve beklenmedik yan etkilere yol açabilir. Küresel değişkenleri değiştirmek yerine, fonksiyonların parametreler alması ve return ile değer döndürmesi daha temiz bir yaklaşımdır.

9.4. nonlocal Anahtar Kelimesi (İç İçe Fonksiyonlar İçin)
Python’da fonksiyonlar iç içe tanımlanabilir (nested functions). İçteki fonksiyon, kendisini çevreleyen (enclosing) fonksiyonun değişkenlerine erişebilir (okuyabilir).

Eğer içteki fonksiyon, ne yerel ne de küresel olan, kendisini çevreleyen fonksiyonun değişkenini değiştirmek isterse, nonlocal anahtar kelimesini kullanır.

def dis_fonksiyon():
kapsayan_degisken = "Dış"
def ic_fonksiyon():
nonlocal kapsayan_degisken # Dış fonksiyonun değişkenini değiştireceğimizi belirtiyoruz
print(f"İç fonksiyon: Değişim öncesi: {kapsayan_degisken}")
kapsayan_degisken = "İç tarafından değiştirildi"
print(f"İç fonksiyon: Değişim sonrası: {kapsayan_degisken}")
print(f"Dış fonksiyon: İç fonksiyon çağrılmadan önce: {kapsayan_degisken}")
ic_fonksiyon() # İç fonksiyonu çağırıp dış değişkeni değiştirmesini sağlıyoruz
print(f"Dış fonksiyon: İç fonksiyon çağrıldıktan sonra: {kapsayan_degisken}")
dis_fonksiyon()
nonlocal, en yakın kapsayan fonksiyondaki değişkeni hedefler, küresel değişkenleri etkilemez.

9.5. LEGB Kuralı
Python, bir değişken ismine erişmeye çalıştığında, ismi bulmak için belirli bir sıra izler. Buna LEGB kuralı denir:

L (Local): Önce mevcut fonksiyonun yerel kapsamına bakar.
E (Enclosing function locals): Eğer yerel kapsamda bulamazsa, varsa iç içe geçmiş fonksiyonların kapsayan fonksiyonlarının yerel kapsamlarına (içten dışa doğru) bakar.
G (Global): Eğer kapsayan kapsamlarda da bulamazsa, modülün küresel kapsamına bakar.
B (Built-in): Eğer küresel kapsamda da bulamazsa, Python’un yerleşik (built-in) isimlerine (print, len, str gibi) bakar.
Eğer isim bu dört kapsamın hiçbirinde bulunamazsa, NameError hatası alınır.

Bölüm 10: Lambda Fonksiyonları (Anonim Fonksiyonlar)
Python, lambda anahtar kelimesi ile küçük, isimsiz (anonim) fonksiyonlar oluşturmaya izin verir. Lambda fonksiyonları genellikle tek bir işlem yapan ve kısa süreliğine ihtiyaç duyulan fonksiyonlar için kullanılır.

Sözdizimi: lambda arguments: expression

lambda: Lambda fonksiyonunu başlatan anahtar kelime.
arguments: Normal fonksiyonlardaki gibi virgülle ayrılmış parametreler.
: (İki nokta üst üste): Argümanlar ile ifadeyi ayırır.
expression: Tek bir ifadedir. Bu ifadenin sonucu lambda fonksiyonunun dönüş değeri olur. lambda içinde return ifadesi veya birden fazla ifade (deyim) kullanılamaz.

Normal fonksiyon tanımı

def kare(x):
return x * x

Eşdeğer lambda fonksiyonu

kare_lambda = lambda x: x * x
print(f"Normal fonksiyon ile 5'in karesi: {kare(5)}") # 25
print(f"Lambda fonksiyon ile 5'in karesi: {kare_lambda(5)}") # 25

İki argümanlı lambda

topla_lambda = lambda a, b: a + b
print(f"Lambda ile 10 + 20 = {topla_lambda(10, 20)}") # 30

Lambda fonksiyonları genellikle başka fonksiyonlara argüman olarak verilirken kullanışlıdır

Örnek: Listeyi elemanların ikinci karakterine göre sıralama

isimler = ["Ali", "Zeynep", "Cem", "Bora"]
isimler.sort(key=lambda isim: isim[1]) # key argümanı bir fonksiyon bekler
print(f"İkinci harfe göre sıralı isimler: {isimler}") # ['Cem', 'Zeynep', 'Ali', 'Bora']

map() ile lambda kullanımı: listedeki her elemanın karesini alma

sayilar = [1, 2, 3, 4, 5]
kareler = list(map(lambda x: x * x, sayilar))
print(f"Sayıların kareleri (map ile): {kareler}") # [1, 4, 9, 16, 25]

filter() ile lambda kullanımı: listedeki çift sayıları filtreleme

cift_sayilar = list(filter(lambda x: x % 2 == 0, sayilar))
print(f"Çift sayılar (filter ile): {cift_sayilar}") # [2, 4]
Lambda fonksiyonları, kısa ve öz olmaları gereken durumlarda kod okunabilirliğini artırabilir, ancak karmaşık işlemler için normal def ile tanımlanmış fonksiyonlar daha uygundur.

Bölüm 11: Fonksiyonlar İçin İyi Uygulamalar (Best Practices)
Etkili ve sürdürülebilir kod yazmak için fonksiyonları kullanırken bazı iyi uygulamaları takip etmek önemlidir:

Anlaşılır İsimlendirme: Fonksiyonlara ne iş yaptıklarını açıkça belirten isimler verin (fiil içeren isimler tercih edilir, örn: hesapla_vergi, dosyayi_oku). PEP 8'e uygun olarak snake_case kullanın.
Tek Sorumluluk Prensibi (Single Responsibility Principle): Her fonksiyon ideal olarak tek bir belirli görevi yerine getirmelidir. Bir fonksiyon çok fazla iş yapıyorsa, onu daha küçük, odaklanmış fonksiyonlara bölmeyi düşünün.
Kısa ve Öz Tutun: Fonksiyonları mümkün olduğunca kısa tutmaya çalışın. Uzun fonksiyonların anlaşılması ve test edilmesi daha zordur.
Docstring Kullanın: Özellikle başkaları tarafından kullanılacak veya karmaşık mantık içeren fonksiyonlar için açıklayıcı docstring’ler yazın.
Yan Etkilerden Kaçının (Mümkünse): Bir fonksiyonun temel görevi dışında programın durumunu (örneğin küresel değişkenleri) değiştirmemesine “yan etkisiz” denir. Yan etkisiz (veya saf — pure) fonksiyonların anlaşılması ve test edilmesi daha kolaydır. Girdi alıp çıktı döndürmeye odaklanın.
Parametre Sayısını Sınırlı Tutun: Çok fazla parametre alan bir fonksiyon, kullanımını zorlaştırabilir ve muhtemelen çok fazla iş yapıyordur. Gerekirse parametreleri bir sözlük veya nesne içinde gruplayın veya fonksiyonu bölün.
Tip İpuçları (Type Hinting): Python 3.5+ ile gelen tip ipuçlarını kullanarak fonksiyon parametrelerinin ve dönüş değerlerinin beklenen tiplerini belirtebilirsiniz. Bu, kodun okunabilirliğini artırır ve statik analiz araçlarına yardımcı olur (ancak Python’un dinamik doğasını değiştirmez).

Tip ipucu örneği def selam(isim: str) -> str: return f"Merhaba, {isim}!"

DRY (Don’t Repeat Yourself): Kod tekrarından kaçınmak için fonksiyonları kullanın. Aynı veya çok benzer kod bloklarını birden fazla yerde görüyorsanız, muhtemelen bir fonksiyona ihtiyaç vardır.
Sonuç
Fonksiyonlar, Python programlamanın vazgeçilmez bir parçasıdır. Kodumuzu yapılandırmak, tekrarı önlemek, okunabilirliği artırmak ve karmaşıklığı yönetmek için güçlü araçlar sunarlar. def ile fonksiyon tanımlama, return ile değer döndürme, farklı argüman türlerini (konumsal, anahtar kelime, varsayılan) anlama ve değişken sayıda argümanı *args ve **kwargs ile yönetebilme becerisi, Python'da yetkin bir geliştirici olmanın temel gereksinimlerindendir.

Değişken kapsamı (LEGB, global, nonlocal) kurallarını bilmek, değişkenlerin nasıl çalıştığını anlamanıza yardımcı olurken, lambda fonksiyonları belirli durumlarda kısa ve etkili çözümler sunar. İyi uygulamaları takip ederek yazdığınız fonksiyonlar, sadece çalışmakla kalmaz, aynı zamanda anlaşılır, sürdürülebilir ve başkaları tarafından kolayca kullanılabilir olur.

Bu rehberde ele alınan kavramları pratik yaparak ve kendi projelerinizde uygulayarak Python fonksiyonları konusundaki ustalığınızı geliştirebilirsiniz.

Abdulkadir Güngör - Kişisel WebSite
Abdulkadir Güngör - Kişisel WebSite
Abdulkadir Güngör - Özgeçmiş
Github
Github
Linkedin