Python Fonksiyonları: Parametreler, Varsayılanlar, *args/**kwargs, Lambda ve Bas
Python Fonksiyon Örnekleri

Python Fonksiyonları: Parametreler, Varsayılanlar, *args/**kwargs, Lambda ve Bas

Python Fonksiyon Örnekleri

8 dk okuma süresi
Bu rehber, Python fonksiyonlarında parametre türlerini (pozisyonel, keyword, positional-only, keyword-only, *args, **kwargs), varsayılan argümanların değerlendirilme zamanını ve mutable default tuzağını, lambda kullanımını ve functools.wraps ile basit dekoratör yazımını örneklerle açıklar.
Python Fonksiyonları: Parametreler, Varsayılanlar, *args/**kwargs, Lambda ve Bas

Python fonksiyonlarını doğru modellemek neden önemli?

Python’da fonksiyonlar, kodu okunabilir, tekrar kullanılabilir ve test edilebilir hale getiren temel yapı taşlarından biridir. Günlük pratikte en çok kafa karışıklığı yaratan konular genellikle şunlardır: parametrelerin nasıl geçirildiği (pozisyonel mi, isimle mi?), varsayılan argümanların ne zaman “oluşturulduğu”, *args/**kwargs ile esnek imza tasarımı, küçük yardımcı fonksiyonlar için lambda kullanımı ve dekoratörlerle (dekoratör/decorator) fonksiyon sarmalama.

Bu yazı, resmi Python dokümantasyonundaki kuralları temel alır (özellikle fonksiyon tanımlama ve parametre davranışı) ve pratik örneklerle pekiştirir. Ana referans: Python Tutorial’daki “Defining Functions / More on Defining Functions” bölümleri (S1) ve dekoratörlerde metadata korumak için functools.wraps dokümantasyonu (S4). Stil tarafında PEP rehberleriyle uyumlu öneriler bulacaksınız (S2).


1) Fonksiyon tanımı ve temel parametre türleri

En temel haliyle Python fonksiyonu def ile tanımlanır ve parametreler parantez içinde belirtilir. Python, argümanları iki ana yoldan alır: pozisyonel (sıraya göre) ve keyword (isim vererek). Resmi dokümantasyon, fonksiyonların bu çağrı modelini ve farklı parametre tiplerini sistematik olarak açıklar (S1).

Pozisyonel vs keyword argümanlar

Aşağıdaki örnek, aynı fonksiyonun hem pozisyonel hem de keyword argümanlarla çağrılabileceğini gösterir:

Kod:

def greet(name, greeting):
    return f"{greeting}, {name}!"

greet("Ada", "Merhaba")
greet(name="Ada", greeting="Merhaba")
greet("Ada", greeting="Merhaba")

Okunabilirlik açısından, özellikle birden çok parametre olduğunda keyword argümanlar çağrının “kendini anlatmasını” sağlar.

Parametre imzasının genel sırası (model)

Python, fonksiyon imzasında parametrelerin belli bir düzenini destekler. Dokümantasyonda bu parçaların birlikte nasıl çalıştığı anlatılır (S1). Pratik bir model olarak şu sırayı düşünün:

  • positional-only (varsa) /
  • positional-or-keyword
  • *args (varsa)
  • keyword-only (varsa) * sonrası
  • **kwargs (varsa)

Her projede positional-only kullanmanız gerekmez; ama kütüphane API’sı tasarlarken (özellikle geriye dönük uyumluluk için) işe yarayabilir.

Positional-only (/) örneği (Python 3.8+)

/ işareti, kendisinden önce gelen parametrelerin yalnızca pozisyonel verilebileceğini ifade eder (S1):

Kod:

def f(a, b, /, c, *, d):
    return a, b, c, d

f(1, 2, 3, d=4)
# f(a=1, b=2, c=3, d=4) # a ve b positional-only olduğu için geçersiz
# f(1, 2, 3, 4) # d keyword-only olduğu için geçersiz

Keyword-only parametreler: Çağrıyı daha net yapmak

Fonksiyonun bazı parametrelerinin mutlaka isimle verilmesini istiyorsanız, imzada * kullanarak onları keyword-only yapabilirsiniz (S1).

Kod:

def connect(host, port, *, timeout=10):
    return f"Connecting to {host}:{port} with timeout={timeout}"

connect("example.com", 443, timeout=5)
# connect("example.com", 443, 5) # timeout isim verilmeden geçilemez

Bu yaklaşım, özellikle “üçüncü parametre neydi?” türü karışıklıkları azaltır.


2) Varsayılan (default) argümanlar ve en yaygın tuzak

Varsayılan değerler, fonksiyon çağrısında parametre verilmezse kullanılacak değerleri tanımlar. Kritik detay: varsayılan argüman ifadeleri, fonksiyon tanımlandığı anda değerlendirilir; her çağrıda tekrar “sıfırdan” oluşturulmaz (S1). Bu kural, özellikle mutable (değiştirilebilir) tiplerde beklenmedik sonuçlara yol açabilir.

Mutable default tuzağı: Liste/dict’i doğrudan default yapmayın

Mutable varsayılanların paylaşılan duruma neden olabileceği sık görülen bir durumdur; yaygın çözüm None kullanıp içeride yeni nesne üretmektir (S1, S3).

Kod:

# Kaçınılması önerilen kullanım
def add_item(item, items=[]):
    items.append(item)
    return items

# Önerilen kalıp
def add_item_safe(item, items=None):
    if items is None:
        items = []
    items.append(item)
    return items

Ne zaman sorun olur? Fonksiyon, çağrılar arasında default listedeki değişiklikleri “hatırladığı” için. Bu davranış her zaman problem olmayabilir; ancak çoğu iş kodunda istenmeyen sürprizlere yol açtığından “None + içeride oluştur” kalıbı daha öngörülebilirdir.

Varsayılanların iyi kullanımı: API ergonomisi

Varsayılanlar, fonksiyonun “kolay kullanım” sürümünü sağlar. İyi bir default seti belirlerken:

  • En sık kullanılan senaryoyu kolaylaştırın.
  • Yan etkisiz (immutable) değerleri tercih edin: None, 0, 1, True/False, "" gibi.
  • İş mantığına göre keyword-only default’lar (ör. timeout=) çağrıyı okunur kılar.

3) *args ve **kwargs: Esnek ama kontrollü imza tasarımı

*args bilinmeyen sayıda pozisyonel argümanı, **kwargs ise bilinmeyen sayıda keyword argümanını yakalamanızı sağlar (S1). Fonksiyonun içinde args bir tuple, kwargs ise bir dict gibi davranır (S1). Bu özellik adaptör fonksiyonlar ve sarmalayıcılar (wrapper) için kullanışlıdır; ancak her şeyi **kwargs içine toplamak okunabilirliği düşürebilir. Mümkünse önce açık isimli parametreleri tercih etmek iyi bir pratiktir (S3).

*args örneği: Birden çok değeri toplamak

Kod:

def total(*numbers):
    s = 0
    for n in numbers:
        s += n
    return s

total(1, 2, 3)
total(10)

**kwargs örneği: Opsiyonel ayarları yakalamak

Kod:

def build_url(base, **params):
    # Basit bir örnek: gerçek hayatta query string için uygun encode işlemi gerekir.
    if not params:
        return base
    query = "&".join(f"{k}={v}" for k, v in params.items())
    return f"{base}?{query}"

build_url("https://example.com", page=2, sort="name")

Not: Yukarıdaki örnek, **kwargs fikrini anlatmak içindir. Üretim kodunda query string oluşturma/encode detayı için standart kütüphanedeki ilgili yardımcıları kullanmak daha doğru bir yaklaşımdır.

İmza okunabilirliği için pratik kurallar

  • Önce açık parametreler: Sık kullanılan ayarları isimli parametre yapın, daha az kullanılan “ileri ayarlar” için **kwargs düşünebilirsiniz.
  • Docstring ile belgeleyin: **kwargs kabul ediyorsanız hangi anahtarların desteklendiğini yazın.
  • Tip/format beklentisini belirtin: Özellikle örneklerde “hangi tip bekleniyor” cümlesi çağrıyı netleştirir.

4) Lambda fonksiyonları: Nerede işe yarar, nerede “def” daha iyi?

Python’daki lambda ifadeleri, tek bir ifadeden oluşan küçük anonim fonksiyonlar tanımlamak içindir. Birden fazla ifade, atama ya da kapsamlı kontrol akışı gerektiğinde normal def daha uygundur (S1).

Lambda için tipik kullanım: key fonksiyonları

Sıralama/anahtar seçimi gibi yerlerde kısa bir fonksiyon vermek yaygındır:

Kod:

users = [
    {"name": "Ada", "age": 36},
    {"name": "Linus", "age": 54},
    {"name": "Grace", "age": 40},
]

sorted_users = sorted(users, key=lambda u: u["age"])

Okunabilirlik eşiği: Ne zaman def yazmalı?

  • Lambda ifadesi uzayıp satır kırmaya başladıysa, genellikle def daha okunur olur.
  • Fonksiyonun bir adı olması, loglama ve hata ayıklama sırasında işleri kolaylaştırır.
  • Docstring gerekiyorsa zaten def tercih edilir.

5) Basit dekoratör: Fonksiyon sarmalama ve functools.wraps

Dekoratörler bir fonksiyonu alıp başka bir fonksiyonla sarmalayarak davranış eklemenizi sağlar. Örneğin loglama veya ölçüm gibi çapraz kesen konularda kullanılabilir. Dekoratör yazarken pratik bir “en iyi uygulama”: sarmalanan fonksiyonun __name__, __doc__ gibi metadata’sını korumak için functools.wraps kullanmaktır (S4).

Örnek: Çağrı sayan dekoratör

Kod:

from functools import wraps

def count_calls(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        wrapper.calls += 1
        return func(*args, **kwargs)
    wrapper.calls = 0
    return wrapper

@count_calls
def hello(name):
    """İsimle selam verir."""
    return f"Merhaba, {name}"

Bu örnekte iki kritik nokta var:

  • *args/**kwargs ile “birçok imzayı” sarmalayabilen bir wrapper yazdık (S1).
  • @wraps(func) sayesinde hello.__name__ ve hello.__doc__ gibi bilgiler daha doğru şekilde korunur (S4).

Dekoratörlerde pratik kontrol listesi

  • wraps kullanın: Dokümantasyon/metadata için.
  • Wrapper imzasını düşünün: Genel sarmalayıcı için *args/**kwargs pratik; beklentileri docstring’te belirtin.
  • Yan etkileri sınırlayın: Örneğin global durum yerine wrapper üzerinde sayaç gibi yerel bir alan tutmak daha kontrollüdür.

6) Docstring örnekleri: Okunabilirlik ve bakım kolaylığı

Docstring, fonksiyonun ne yaptığını ve nasıl kullanılacağını anlatan ilk dokümantasyon katmanıdır. PEP rehberleri, kod stilinde tutarlılık konusunda yol gösterir (S2). Ekip içinde tek bir docstring formatında anlaşmak (ör. kısa açıklama + parametreler + dönüş) bakım maliyetini azaltır.

Basit ve pratik docstring şablonu

Kod:

def area(width, height):
    """Dikdörtgen alanını hesaplar.

    Args:
        width: Genişlik (sayı).
        height: Yükseklik (sayı).

    Returns:
        Alan (width * height).
    """
    return width * height

Not: Amaç tek bir “zorunlu format” dayatmak değil; tutarlılık ve açıklıktır.


7) Hızlı uygulama: Fonksiyon imzanızı tasarlarken 10 dakikalık rehber

  1. Minimum imza: Önce en az parametreyle çalışan bir def yazın.
  2. Okunabilir çağrılar: 3+ parametrede kritik seçenekleri keyword-only yapmayı değerlendirin (S1).
  3. Varsayılanları gözden geçirin: Mutable default kullanmayın; gerekiyorsa None + içeride oluşturma kalıbını kullanın (S1, S3).
  4. *args/**kwargs gerçekten gerekli mi? Sadece “ileride lazım olur” diye eklemek yerine gerçek ihtiyaca göre ekleyin.
  5. Docstring yazın: Parametre ve dönüş değerini en azından bir-iki satırla belirtin (S2).
  6. Dekoratör varsa wraps ekleyin: Metadata kaybını önlemek için (S4).

Sonuç

Python fonksiyonlarında “küçük” görünen detaylar (varsayılanların değerlendirilme zamanı, keyword-only/positional-only kuralları, dekoratörlerde metadata) proje büyüdükçe bakım maliyetini doğrudan etkiler. Bu rehberdeki örnekleri kendi kod tabanınıza uyarlarken önce okunabilirlik ve öngörülebilirlik hedefleyin; emin olmadığınız noktalarda küçük testlerle davranışı doğrulamak iyi bir pratiktir.

Yorumlar

Henüz yorum yapılmamış. İlk yorumu sen yaz.