Parametreler: *args, **kwargs, Default
Fonksiyon tanımlamayı öğrendin. Ama gerçek güç, fonksiyonlara nasıl veri aktardığında ortaya çıkar. Python'un parametre sistemi inanılmaz esnek — aynı fonksiyonu 3 farklı şekilde çağırabilir, isteğe bağlı parametreler ekleyebilir, hatta kaç parametre geleceğini bilmeden bile fonksiyon yazabilirsin.
Bu derste Python'un tüm parametre türlerini, sıralama kurallarını ve sık yapılan hataları detaylıca göreceğiz.
Terimler: Parametre vs Argüman
Önce terminolojiyi netleştirelim çünkü herkes bunları karıştırır:
Parametre (parameter): Fonksiyon tanımında yazılan değişken adları
Argüman (argument): Fonksiyon çağrılırken verilen değerler
def selamla(isim): # "isim" bir PARAMETRE
return f"Merhaba {isim}!"
selamla("Ayşe") # "Ayşe" bir ARGÜMANGünlük konuşmada çoğu kişi ikisini birbirinin yerine kullanır ve dünya yıkılmaz. Ama teknik tartışmalarda farkı bilmek işe yarar.
Positional vs Keyword Arguments
Python'da fonksiyon çağırırken argümanları iki şekilde geçebilirsin:
Positional (Konumsal) Arguments
Argümanlar sırayla eşleşir. İlk argüman ilk parametreye, ikinci argüman ikinci parametreye gider:
def bilgi_goster(ad, yas, sehir):
print(f"{ad}, {yas} yaşında, {sehir}'da yaşıyor.")
# Positional: sıra önemli!
bilgi_goster("Ahmet", 25, "İstanbul")
# Ahmet, 25 yaşında, İstanbul'da yaşıyor.
# Sırayı karıştırırsan anlam da karışır
bilgi_goster(25, "İstanbul", "Ahmet")
# 25, İstanbul yaşında, Ahmet'da yaşıyor. ← Anlamsız!Keyword (İsimli) Arguments
Argümanları parametre adıyla geçersin. Sıra önemli değil:
def bilgi_goster(ad, yas, sehir):
print(f"{ad}, {yas} yaşında, {sehir}'da yaşıyor.")
# Keyword: sıra önemli değil!
bilgi_goster(yas=25, sehir="İstanbul", ad="Ahmet")
# Ahmet, 25 yaşında, İstanbul'da yaşıyor. ✅
# İkisini karıştırabilirsin (ama positional önce gelmeli)
bilgi_goster("Ahmet", sehir="İstanbul", yas=25)
# Ahmet, 25 yaşında, İstanbul'da yaşıyor. ✅Kural: Positional argümanlar her zaman keyword argümanlardan önce gelir.
# ❌ Hata: positional, keyword'den sonra gelemez
bilgi_goster(ad="Ahmet", 25, "İstanbul")
# SyntaxError: positional argument follows keyword argumentNe Zaman Hangisini Kullanmalı?
Positional: Az sayıda, sırası belli argümanlar için.
topla(3, 5)gayet anlaşılır.Keyword: Çok parametreli fonksiyonlarda, boolean parametrelerde veya varsayılan değerlerle çalışırken.
dosya_ac(yol="data.txt", encoding="utf-8", readonly=True)çok daha okunabilir.
Default (Varsayılan) Parameter Values
Parametrelere varsayılan değer atayabilirsin. Böylece çağıran kişi o parametreyi vermezse varsayılan kullanılır:
def kahve_siparis(boy="orta", sut=True, seker=1):
"""Kahve siparişi oluşturur."""
sut_str = "sütlü" if sut else "sütsüz"
print(f"{boy.capitalize()} boy, {sut_str}, {seker} şekerli kahve")
# Tüm varsayılanları kullan
kahve_siparis()
# Orta boy, sütlü, 1 şekerli kahve
# Sadece boy değiştir
kahve_siparis("büyük")
# Büyük boy, sütlü, 1 şekerli kahve
# Sadece şekeri değiştir
kahve_siparis(seker=0)
# Orta boy, sütlü, 0 şekerli kahve
# Hepsini değiştir
kahve_siparis("küçük", False, 3)
# Küçük boy, sütsüz, 3 şekerli kahveBu, fonksiyonları çok esnek yapar. Kullanıcı sadece değiştirmek istediği parametreleri verir, gerisini varsayılanlara bırakır.
Kural: Varsayılan değeri olan parametreler, olmayan parametrelerden sonra gelmeli:
# ✅ Doğru: default'suz önce, default'lu sonra
def kayit_olustur(ad, soyad, aktif=True, rol="kullanici"):
pass
# ❌ Hata: default'suz parametre default'lunun arkasında
def kayit_olustur(ad, aktif=True, soyad):
pass
# SyntaxError: non-default argument follows default argumentPratik Örnek: Esnek Loglama
import datetime
def log(mesaj, seviye="INFO", zaman_damgasi=True):
"""Esnek loglama fonksiyonu."""
cikti = ""
if zaman_damgasi:
simdi = datetime.datetime.now().strftime("%H:%M:%S")
cikti += f"[{simdi}] "
cikti += f"[{seviye}] {mesaj}"
print(cikti)
log("Uygulama başlatıldı")
# [14:30:22] [INFO] Uygulama başlatıldı
log("Disk dolu!", seviye="WARN")
# [14:30:22] [WARN] Disk dolu!
log("Debug bilgisi", seviye="DEBUG", zaman_damgasi=False)
# [DEBUG] Debug bilgisi*args: Değişken Sayıda Positional Argüman
Bazen fonksiyona kaç argüman geleceğini bilemezsin. *args ile sınırsız sayıda positional argüman kabul edebilirsin:
def topla(*args):
"""İstediğin kadar sayıyı toplar."""
print(f"Gelen argümanlar: {args}")
print(f"Tipi: {type(args)}") # <class 'tuple'>
return sum(args)
print(topla(1, 2)) # 3
print(topla(1, 2, 3, 4, 5)) # 15
print(topla(10)) # 10
print(topla()) # 0*args bir tuple olarak gelir. İsim "args" olmak zorunda değil — *sayilar, *elemanlar da yazabilirsin. Önemli olan * yıldızı.
def en_buyuk_bul(*sayilar):
"""Verilen sayılardan en büyüğünü bulur."""
if not sayilar:
return None
en_buyuk = sayilar[0]
for sayi in sayilar[1:]:
if sayi > en_buyuk:
en_buyuk = sayi
return en_buyuk
print(en_buyuk_bul(3, 7, 2, 9, 1)) # 9
print(en_buyuk_bul(42)) # 42
print(en_buyuk_bul()) # NoneNormal Parametrelerle Birlikte Kullanım
*args normal parametrelerle beraber kullanılabilir:
def raporla(baslik, *satirlar):
"""Başlık ve altına satırlar yazar."""
print(f"=== {baslik} ===")
for i, satir in enumerate(satirlar, 1):
print(f" {i}. {satir}")
raporla("Yapılacaklar", "Market alışverişi", "Fatura ödeme", "Spor")Çıktı:
=== Yapılacaklar ===
1. Market alışverişi
2. Fatura ödeme
3. Sporİlk argüman baslik'a gider, geri kalan her şey *satirlar tuple'ına toplanır.
**kwargs: Değişken Sayıda Keyword Argüman
**kwargs ile sınırsız sayıda isimli argüman kabul edebilirsin. Bu argümanlar bir dictionary olarak gelir:
def profil_olustur(**kwargs):
"""Dinamik profil oluşturur."""
print(f"Gelen veri: {kwargs}")
print(f"Tipi: {type(kwargs)}") # <class 'dict'>
for anahtar, deger in kwargs.items():
print(f" {anahtar}: {deger}")
profil_olustur(ad="Ayşe", yas=28, sehir="Ankara")Çıktı:
Gelen veri: {'ad': 'Ayşe', 'yas': 28, 'sehir': 'Ankara'}
Tipi: <class 'dict'>
ad: Ayşe
yas: 28
sehir: Ankara**kwargs ismi de zorunlu değil — **bilgiler, **options da olabilir. Önemli olan ** çift yıldız.
Pratik: Esnek HTML Tag Oluşturucu
def html_tag(tag, icerik, **attributes):
"""HTML tag'i oluşturur."""
attr_str = ""
for anahtar, deger in attributes.items():
# class_ → class (Python'da class reserved word)
attr_adi = anahtar.rstrip("_")
attr_str += f' {attr_adi}="{deger}"'
return f"<{tag}{attr_str}>{icerik}</{tag}>"
print(html_tag("p", "Merhaba Dünya"))
# <p>Merhaba Dünya</p>
print(html_tag("div", "İçerik", class_="container", id="main"))
# <div class="container" id="main">İçerik</div>
print(html_tag("a", "Tıkla", href="https://python.org", target="_blank"))
# <a href="https://python.org" target="_blank">Tıkla</a>*args ve **kwargs Birlikte
İkisi aynı fonksiyonda kullanılabilir:
def super_fonksiyon(*args, **kwargs):
"""Her şeyi kabul eden fonksiyon."""
print(f"Positional: {args}")
print(f"Keyword: {kwargs}")
super_fonksiyon(1, 2, 3, ad="Ali", yas=30)
# Positional: (1, 2, 3)
# Keyword: {'ad': 'Ali', 'yas': 30}Bu pattern özellikle wrapper fonksiyonlar ve decorator'lar yazarken çok kullanılır:
def loglayici(fonksiyon):
"""Fonksiyon çağrılarını loglar."""
def wrapper(*args, **kwargs):
print(f"Çağrılıyor: {fonksiyon.__name__}")
print(f" args: {args}")
print(f" kwargs: {kwargs}")
sonuc = fonksiyon(*args, **kwargs)
print(f" Sonuç: {sonuc}")
return sonuc
return wrapper*args ve **kwargs wrapper'ın herhangi bir fonksiyonu sarmasını sağlar — kaç parametre alırsa alsın.
Keyword-Only Arguments (Sadece İsimle Geçilebilen)
Python 3'te, * işaretinden sonra gelen parametreler sadece keyword olarak geçilebilir:
def dosya_yaz(icerik, *, dosya_adi, encoding="utf-8"):
"""Dosyaya yazar. dosya_adi sadece keyword olarak geçilebilir."""
print(f"'{dosya_adi}' dosyasına yazılıyor ({encoding})...")
print(f"İçerik: {icerik}")
# ✅ Doğru: keyword olarak geç
dosya_yaz("Merhaba", dosya_adi="test.txt")
dosya_yaz("Veri", dosya_adi="data.csv", encoding="latin-1")
# ❌ Hata: positional olarak geçemezsin
# dosya_yaz("Merhaba", "test.txt")
# TypeError: dosya_yaz() takes 1 positional argument but 2 were given* tek başına "burada positional argümanlar bitiyor" demektir. Ondan sonraki her şey keyword-only.
Neden Keyword-Only?
Boolean parametreler için özellikle kullanışlı:
# ❌ Bu çağrı ne anlama geliyor? Kim bilebilir?
dosya_oku("data.txt", True, False, True)
# ✅ Çok daha anlaşılır!
dosya_oku("data.txt", binary=True, cache=False, verbose=True)Keyword-only zorunluluğu koyarak API'yi yanlış kullanımdan korursun.
def connect(host, port, *, timeout=30, retry=3, ssl=False):
"""Sunucuya bağlanır. Opsiyonel parametreler keyword-only."""
print(f"Bağlanılıyor: {host}:{port}")
print(f" timeout={timeout}, retry={retry}, ssl={ssl}")
# Temiz, anlaşılır çağrı
connect("api.example.com", 443, ssl=True, timeout=10)*args ile Birlikte
*args kullandığında, ondan sonraki parametreler zaten keyword-only olur:
def log(*mesajlar, seviye="INFO", dosya=None):
for mesaj in mesajlar:
satir = f"[{seviye}] {mesaj}"
print(satir)
log("Başladı", "İşleniyor", "Bitti", seviye="DEBUG")Positional-Only Arguments (Python 3.8+)
Python 3.8 ile / operatörü geldi. /'den önceki parametreler sadece positional olarak geçilebilir:
def us_al(taban, us, /):
"""Taban ve üs sadece positional olarak geçilebilir."""
return taban ** us
# ✅ Doğru: positional
print(us_al(2, 10)) # 1024
# ❌ Hata: keyword olarak geçilemez
# print(us_al(taban=2, us=10))
# TypeError: us_al() got some positional-only arguments passed as keyword argumentsNeden Positional-Only?
Parametre ismi değişebilir: API'yi bozmadan parametre adını değiştirebilirsin
Doğal kullanım:
len(obj)doğal,len(obj=mylist)garipPerformans: CPython'da positional-only parametreler biraz daha hızlı
Python'un kendi fonksiyonlarının çoğu positional-only:
# Bu çalışmaz:
# len(obj=[1,2,3]) # TypeError
# print(sep=" ") # Bu çalışır çünkü sep keyword-only
# len, range, abs gibi fonksiyonlar positional-only/ ve * Birlikte
Hem positional-only hem keyword-only parametreleri aynı fonksiyonda kullanabilirsin:
def karma(pos_only, /, normal, *, kw_only):
"""Üç tür parametre bir arada."""
print(f"pos_only={pos_only}, normal={normal}, kw_only={kw_only}")
# ✅ Doğru kullanımlar
karma(1, 2, kw_only=3) # pos_only=1, normal=2, kw_only=3
karma(1, normal=2, kw_only=3) # pos_only=1, normal=2, kw_only=3
# ❌ Hatalar
# karma(pos_only=1, normal=2, kw_only=3) # pos_only keyword olamaz!
# karma(1, 2, 3) # kw_only keyword olmalı!# Daha gerçekçi bir örnek
def arama(query, /, *, limit=10, offset=0, siralama="relevance"):
"""Arama yapar. Query positional-only, geri kalan keyword-only."""
print(f"Aranan: '{query}' (limit={limit}, offset={offset})")
arama("python dersleri", limit=5)
arama("machine learning", limit=20, siralama="date")Parametre Sırası Kuralı
Tüm parametre türlerini bir arada kullandığında belirli bir sıra izlemelisin:
def fonksiyon(pos_only, /, normal, *args, kw_only, **kwargs):Sıra:
Positional-only parametreler (
/öncesi)Normal parametreler (positional veya keyword)
`*args` (variable positional)
Keyword-only parametreler (
*veya*argssonrası)`kwargs`** (variable keyword)
def tam_ornek(a, b, /, c, d=10, *args, e, f=20, **kwargs):
"""Tüm parametre türleri bir arada."""
print(f"Positional-only: a={a}, b={b}")
print(f"Normal: c={c}, d={d}")
print(f"*args: {args}")
print(f"Keyword-only: e={e}, f={f}")
print(f"**kwargs: {kwargs}")
tam_ornek(1, 2, 3, 4, 5, 6, e=100, g=200, h=300)Çıktı:
Positional-only: a=1, b=2
Normal: c=3, d=4
*args: (5, 6)
Keyword-only: e=100, f=20
**kwargs: {'g': 200, 'h': 300}💡 İpucu: Bu kadar karmaşık parametre kombinasyonunu pratikte nadiren kullanırsın. Ama Python'un parametre sistemini tam olarak anlamak için bilmen gerekiyor. Gerçek projelerde genellikle 2-3 parametre türünü bir arada kullanırsın, hepsini birden değil.
⚠️ Mutable Default Argument TUZAĞI
Bu, Python'un en ünlü tuzaklarından biri. Acemi-kıdemli fark etmez, herkes en az bir kere düşer.
Tuzak: def f(lst=[])
def listeye_ekle(eleman, liste=[]):
"""BU FONKSİYON BOZUK! Kullanma!"""
liste.append(eleman)
return liste
# İlk çağrı — sorun yok gibi
print(listeye_ekle("elma")) # ['elma'] ✅
# İkinci çağrı — HOP!
print(listeye_ekle("armut")) # ['elma', 'armut'] 😱
# Üçüncü çağrı — gittikçe büyüyor!
print(listeye_ekle("muz")) # ['elma', 'armut', 'muz'] 😱😱Ne oldu? Her çağrıda yeni boş bir liste bekliyordun ama önceki elemanlar hâlâ orada!
Neden?
Python'da default değerler fonksiyon tanımlandığında bir kere oluşturulur, her çağrıda yeniden oluşturulmaz. Yani [] bir kere yaratılır ve tüm çağrılar aynı listeyi paylaşır.
Bunu kanıtlayalım:
def tuzak(lst=[]):
print(f" Liste id: {id(lst)}")
lst.append(1)
return lst
print("Çağrı 1:")
tuzak() # Liste id: 140234567890 ← bu id'yi not et
print("Çağrı 2:")
tuzak() # Liste id: 140234567890 ← AYNI id! Aynı nesne!
print("Çağrı 3:")
tuzak() # Liste id: 140234567890 ← hâlâ aynı!Çözüm: None Pattern
def listeye_ekle(eleman, liste=None):
"""Doğru yol: None kullan, fonksiyon içinde oluştur."""
if liste is None:
liste = [] # Her çağrıda yeni liste oluşturulur
liste.append(eleman)
return liste
print(listeye_ekle("elma")) # ['elma'] ✅
print(listeye_ekle("armut")) # ['armut'] ✅ Her seferinde yeni!
print(listeye_ekle("muz")) # ['muz'] ✅
# Mevcut listeye de ekleyebilirsin
meyveler = ["çilek"]
print(listeye_ekle("karpuz", meyveler)) # ['çilek', 'karpuz']⚠️ Dikkat: Bu tuzak sadece mutable (değiştirilebilir) default değerler için geçerli:
list,dict,set. Immutable değerler (int,str,tuple,None,True) için sorun yok.
# ✅ Bunlar güvenli
def f(x=0): pass # int immutable
def f(s="abc"): pass # str immutable
def f(t=(1,2)): pass # tuple immutable
# ❌ Bunlar tuzak!
def f(lst=[]): pass # list mutable → TUZAK
def f(d={}): pass # dict mutable → TUZAK
def f(s=set()): pass # set mutable → TUZAKBu tuzağı bildiğine göre her zaman None pattern kullan:
def fonksiyon(veri=None, config=None):
if veri is None:
veri = []
if config is None:
config = {}
# ...Unpacking ile Fonksiyon Çağırma
Bir listeyi veya dictionary'yi "açarak" fonksiyona argüman olarak geçebilirsin.
* ile Liste/Tuple Unpacking
def toplam(a, b, c):
return a + b + c
sayilar = [10, 20, 30]
# ❌ Bu çalışmaz
# toplam(sayilar) # TypeError: 1 argüman verildi, 3 bekleniyor
# ✅ * ile aç
print(toplam(*sayilar)) # 60
# Aslında toplam(10, 20, 30) çağrılıyorBu, range() gibi fonksiyonlarla da çalışır:
aralik = (2, 10, 3)
print(list(range(*aralik))) # [2, 5, 8]
# range(2, 10, 3) ile aynı** ile Dictionary Unpacking
def kullanici_olustur(ad, soyad, yas, sehir):
return f"{ad} {soyad}, {yas} yaşında, {sehir}"
bilgiler = {
"ad": "Zeynep",
"soyad": "Kaya",
"yas": 27,
"sehir": "İzmir"
}
# ** ile dictionary'yi aç
print(kullanici_olustur(**bilgiler))
# Zeynep Kaya, 27 yaşında, İzmir
# Aslında kullanici_olustur(ad="Zeynep", soyad="Kaya", yas=27, sehir="İzmir") çağrılıyorİkisini Birlikte Kullanma
def rapor(baslik, *satirlar, **meta):
print(f"\n{'='*40}")
print(f" {baslik}")
print(f"{'='*40}")
for satir in satirlar:
print(f" • {satir}")
if meta:
print(f"{'─'*40}")
for k, v in meta.items():
print(f" {k}: {v}")
# Unpacking ile çağır
konular = ["Giriş", "Analiz", "Sonuç"]
detaylar = {"yazar": "Ayşe", "tarih": "2024-01-15"}
rapor("Proje Raporu", *konular, **detaylar)Çıktı:
========================================
Proje Raporu
========================================
• Giriş
• Analiz
• Sonuç
────────────────────────────────────────
yazar: Ayşe
tarih: 2024-01-15Unpacking ile Dictionary Birleştirme
Python 3.5+ ile ** kullanarak dictionary'leri birleştirebilirsin:
varsayilan_ayarlar = {"tema": "açık", "dil": "tr", "font_boyut": 14}
kullanici_ayarlari = {"tema": "koyu", "font_boyut": 16}
# Kullanıcı ayarları varsayılanları override eder
ayarlar = {**varsayilan_ayarlar, **kullanici_ayarlari}
print(ayarlar)
# {'tema': 'koyu', 'dil': 'tr', 'font_boyut': 16}Son gelen aynı anahtarı ezer. Bu pattern konfigürasyon yönetiminde çok kullanılır.
Pratik: Esnek print_info() Fonksiyonu
Öğrendiklerimizi birleştirip gerçek hayatta kullanılabilecek esnek bir fonksiyon yazalım:
def print_info(baslik="Bilgi", /, *args, ayirici="─", genislik=40, **kwargs):
"""Esnek bilgi kartı yazdırır.
Args:
baslik: Kart başlığı (positional-only)
*args: Ek satırlar
ayirici: Ayırıcı karakter
genislik: Kart genişliği
**kwargs: Anahtar-değer çiftleri
"""
print(ayirici * genislik)
print(f" 📋 {baslik}")
print(ayirici * genislik)
# Sırasız satırlar (*args)
for arg in args:
print(f" {arg}")
# Anahtar-değer çiftleri (**kwargs)
if kwargs:
max_key_len = max(len(str(k)) for k in kwargs)
for key, value in kwargs.items():
# snake_case'i güzel formata çevir
guzel_key = key.replace("_", " ").title()
print(f" {guzel_key:<{max_key_len + 5}}: {value}")
print(ayirici * genislik)
# Basit kullanım
print_info("Kullanıcı", ad="Mehmet", soyad="Demir", yas=32)
# Daha detaylı
print_info(
"Proje Durumu",
"⚡ Acil güncelleme gerekli",
"🔄 Sprint 3 devam ediyor",
proje_adi="E-Ticaret",
durum="Geliştirmede",
tamamlanma="65%",
son_guncelleme="2024-01-15",
ayirici="═",
genislik=50
)Çıktı:
────────────────────────────────────────
📋 Kullanıcı
────────────────────────────────────────
Ad : Mehmet
Soyad : Demir
Yas : 32
────────────────────────────────────────
══════════════════════════════════════════════════
📋 Proje Durumu
══════════════════════════════════════════════════
⚡ Acil güncelleme gerekli
🔄 Sprint 3 devam ediyor
Proje Adi : E-Ticaret
Durum : Geliştirmede
Tamamlanma : 65%
Son Guncelleme : 2024-01-15
══════════════════════════════════════════════════Bu tek fonksiyonda gördüğün parametreler:
baslik→ positional-only (/sonrası)*args→ değişken sayıda ek satırayirici,genislik→ keyword-only (varsayılanlı)**kwargs→ istediğin kadar anahtar-değer
Type Hints ile Parametreleri Belgeleme
Python 3.5+ ile parametrelerin tipini belirtebilirsin. Bu çalışma zamanında kontrol yapmaz ama dokümantasyon ve IDE desteği için harika:
def hesapla_bmi(kilo: float, boy: float) -> float:
"""BMI hesaplar."""
return kilo / (boy ** 2)
def selamla(isim: str, resmi: bool = False) -> str:
"""İsme göre selamlama döndürür."""
if resmi:
return f"Sayın {isim}, hoş geldiniz."
return f"Selam {isim}!"
# Type hint'ler çalışmayı DEĞİŞTİRMEZ
# Yanlış tip versen bile Python hata vermez (runtime'da)
print(hesapla_bmi("yetmiş", "bir_yetmiş")) # Çalışır ama hata verirDaha karmaşık type hint'ler:
from typing import Optional
def ara(
query: str,
limit: int = 10,
filtreler: Optional[dict] = None
) -> list[dict]:
"""Arama yapar ve sonuçları döndürür."""
if filtreler is None:
filtreler = {}
# ... arama mantığı
return []💡 İpucu: Type hint'ler zorunlu değil ama büyük projelerde hayat kurtarır. IDE'ler (VS Code, PyCharm) type hint'leri kullanarak otomatik tamamlama ve hata tespiti yapar.
mypygibi araçlar type hint'leri statik olarak kontrol edebilir.
Sık Yapılan Hatalar
1. Argüman Sayısı Uyuşmazlığı
def topla(a, b):
return a + b
# topla(1) # TypeError: missing 1 required positional argument: 'b'
# topla(1, 2, 3) # TypeError: takes 2 positional arguments but 3 were given2. Keyword Argümanı İki Kere Verme
def f(a, b):
return a + b
# f(1, a=2) # TypeError: f() got multiple values for argument 'a'
# İlk argüman a=1 oldu, sonra a=2 diyorsun → çakışma!3. Bilinmeyen Keyword Argümanı
def f(a, b):
return a + b
# f(a=1, b=2, c=3) # TypeError: f() got an unexpected keyword argument 'c'
# **kwargs yoksa fazladan keyword argüman veremezsin4. Mutable Default (Tekrar!)
Bu kadar önemli ki bir kere daha vurgulayalım:
# ❌ ASLA böyle yapma
def kotu(sozluk={}):
sozluk["sayac"] = sozluk.get("sayac", 0) + 1
return sozluk
print(kotu()) # {'sayac': 1}
print(kotu()) # {'sayac': 2} ← aynı dict!
# ✅ HER ZAMAN böyle yap
def iyi(sozluk=None):
if sozluk is None:
sozluk = {}
sozluk["sayac"] = sozluk.get("sayac", 0) + 1
return sozluk
print(iyi()) # {'sayac': 1}
print(iyi()) # {'sayac': 1} ✅ her seferinde yeni dictÖzet
Positional argümanlar sırayla, keyword argümanlar isimle eşleşir. İkisi karışık kullanılabilir ama positional her zaman önce gelir.
Default değerler parametrelere varsayılan atamayı sağlar. Default'lu parametreler default'suzlardan sonra gelmelidir.
`*args` sınırsız positional argümanı tuple olarak toplar; `kwargs`** sınırsız keyword argümanı dictionary olarak toplar.
Keyword-only (
*sonrası) ve positional-only (/öncesi) parametreler API tasarımını daha güvenli yapar.Mutable default argument tuzağı Python'un en tehlikeli gotcha'larından biridir.
def f(lst=[])yerine her zamandef f(lst=None)kullan.Unpacking (
*liste,**dict) ile koleksiyonları açarak fonksiyonlara argüman olarak geçebilirsin. Bu özellikle konfigürasyon ve wrapper fonksiyonlarda çok işe yarar.
AI Asistan
Sorularını yanıtlamaya hazır