Python'da *args ve **kwargs, bir fonksiyonun önceden kaç parametre alacağını bilmediğiniz durumlarda esnek argüman toplamayı sağlayan iki özel sözdizimidir. *args, fonksiyona gönderilen pozisyonel argümanları bir tuple içinde toplarken; **kwargs, anahtar kelime argümanlarını bir sözlük (dict) içinde toplar. İkisi birbirinin alternatifi değil, tamamlayıcısıdır: biri sırayla gelen değerleri, diğeri isimlendirilmiş değerleri yakalar. Bu makalede mekanizmanın nasıl çalıştığını, ne zaman gerçekten gerekli olduğunu ve ne zaman kodu okunmaz hale getirdiğini örneklerle göreceksiniz.
*args ve **kwargs Ne İşe Yarar? Mekanizmayı Anlamak
Bir fonksiyon tanımında parametre isminin önüne tek yıldız (*) koyduğunuzda, o parametre fonksiyona gönderilen tüm fazladan pozisyonel argümanları bir tuple nesnesinde toplar. Aynı şekilde iki yıldız (**) ile tanımlanan parametre, isim=değer biçiminde gönderilen tüm anahtar kelime argümanlarını bir dict nesnesinde toplar. Burada kritik nokta, yıldızların operatör değil, Python yorumlayıcısına "kalan argümanları burada topla" talimatı veren birer sözdizimi işaretçisi olmasıdır. args ve kwargs isimleri bir kural değil yalnızca yaygın bir gelenektir; fonksiyon aynı mekanizmayla *degerler veya **ayarlar gibi farklı isimlerle de tanımlanabilir.
Python'un fonksiyon imzasında izin verdiği parametre sırası sabittir: önce normal (pozisyonel veya varsayılan değerli) parametreler, ardından *args, en sonda ise **kwargs gelir. Bu sıra rastgele değildir; yorumlayıcı bir çağrıyı işlerken önce açıkça isimlendirilmiş veya sırasıyla eşleşen normal parametreleri doldurur, geriye kalan pozisyonel değerleri *args'a, geriye kalan isimlendirilmiş değerleri de **kwargs'a aktarır. Örneğin ad, *args, **kwargs biçiminde tanımlanmış bir fonksiyonda ad her zaman ilk pozisyonel değeri alır; eğer **kwargs önce yazılırsa Python bunu bir söz dizimi hatası olarak değerlendirir, çünkü sözlük yapısının hangi argümanları kapsayacağı belirsizleşir. Bu yüzden parametre sırasını ezbere değil, mantığını kavrayarak öğrenmek kalıcı olur.
Bu mekanizmanın nerede takılıp kaldığınızı görmek, konuyu gerçekten özümsediğinizi anlamanın en hızlı yoludur. Python bilgi seviyeni ölçen kısa test ile *args ve **kwargs gibi orta seviye konularda ne kadar rahat olduğunuzu birkaç dakikada görebilir, eksik kaldığınız noktaları netleştirebilirsiniz.
Fonksiyon Çağrısında Packing ve Unpacking Farkı
*args ve **kwargs iki farklı bağlamda iki farklı iş yapar ve bu ayrımı netleştirmemek en sık karışıklık sebebidir. Fonksiyon tanımında kullanıldıklarında "packing" (toplama) yaparlar: dağınık gelen argümanları tek bir tuple veya dict içinde birleştirirler. Fonksiyon çağrısında kullanıldıklarında ise tam tersini yaparlar; zaten var olan bir listeyi, tuple'ı veya dict'i tek tek argümanlara "unpacking" (paketten çıkarma) yoluyla dağıtırlar. Yani aynı yıldız işaretleri, konumlarına göre birbirinin tersi iki işlevi üstlenir.
Bunu somutlaştırmak için bir liste veya sözlüğü doğrudan bir fonksiyona dağıtmayı düşünün:
def toplam(a, b, c):
return a + b + c
sayilar = [3, 5, 7]
print(toplam(*sayilar)) # sayilar listesi 3 ayrı argümana açılır
ayarlar = {"a": 1, "b": 2, "c": 3}
print(toplam(**ayarlar)) # dict, isim=değer eşleşmesiyle dağıtılır
Burada toplam fonksiyonunun tanımında herhangi bir *args veya **kwargs yoktur; sıradan üç parametre vardır. Esnekliği sağlayan, çağrı tarafında kullanılan * ve ** işaretleridir. Bu iki kullanımı karıştırmamak önemlidir: bir fonksiyonu tanımlarken *args yazmak "bana kaç tane pozisyonel argüman gelirse gelsin topla" demektir, bir fonksiyonu çağırırken *liste yazmak ise "elimdeki bu koleksiyonu tek tek argümanlara aç" demektir. Aynı sözdizimi öğesinin bağlama göre zıt anlam taşıması, yeni başlayanların en çok takıldığı noktalardan biridir; bu yüzden hangi tarafta (tanım mı, çağrı mı) olduğunuzu her zaman önce netleştirmek gerekir.
Esnek İmzanın Gerçekten Gerekli Olduğu Senaryolar

*args ve **kwargs'ı her fonksiyonda kullanmak cazip görünse de, bu yapı asıl değerini belirli senaryolarda gösterir. En tipik örnek decorator (dekoratör) ve wrapper fonksiyonlardır: bir dekoratör, sarmaladığı fonksiyonun hangi parametrelerle çağrılacağını önceden bilemez. Loglama, zaman ölçme veya yetkilendirme gibi amaçlarla yazılan bir dekoratör, altındaki fonksiyonun imzasını taklit edebilmek için mutlaka *args, **kwargs kombinasyonuna ihtiyaç duyar; aksi halde yalnızca belirli sayıda parametre alan fonksiyonları sarmalayabilir, genel amaçlı olmaktan çıkar.
Benzer zorunluluk, sınıf miras zincirlerinde ve API istemcilerinde de karşımıza çıkar:
- Bir alt sınıf, üst sınıfın
__init__metodunu çağırırken üst sınıfın parametre listesini bilmeden veya değiştirmeden ek argümanları iletmek istediğindesuper().__init__(*args, **kwargs)kullanımı üst sınıf imzasında değişiklik olsa bile alt sınıf kodunu bozulmaktan korur. - Bir API istemcisi yazarken, dış servise gönderilecek isteğe bağlı başlık veya sorgu parametrelerinin sayısı isteğe göre değişebildiğinden, bu parametreleri tek tek tanımlamak yerine **kwargs ile toplayıp istek gövdesine aktarmak kodu sadeleştirir.
- Çok sayıda opsiyonel ayarı olan bir yardımcı fonksiyon (örneğin bir raporlama veya biçimlendirme fonksiyonu) her ayar için ayrı parametre tanımlamak yerine **kwargs üzerinden varsayılan değerlerle birlikte gelen ayarları okuyup uygulayabilir; bu, fonksiyon çağrılarını gereksiz uzun parametre listelerinden kurtarır.
Bu senaryoların ortak noktası, fonksiyonun kendisinin değil, onu çağıran kodun hangi argümanları göndereceğinin belirsiz veya değişken olmasıdır. Bu tür esnek imza tasarımı, temel fonksiyon bilgisinden orta seviyeye geçerken karşılaşılan konulardan biridir; canlı sınıflı Python eğitimi sürecinde bu kalıpların gerçek proje örnekleri üzerinde nerede işe yaradığı ve nerede gereksiz karmaşıklık yarattığı uygulamalı olarak ele alınır.
Uygulamalı Örnek: Decorator İçinde *args ve **kwargs
Python'da *args ve **kwargs ikilisinin en somut faydası, bir decorator yazarken ortaya çıkar. Bir decorator, sarmaladığı fonksiyonun kaç parametre aldığını, bu parametrelerin isimlerini veya sırasını bilmek zorunda değildir; çünkü esnek imza sayesinde ne gelirse gelsin yakalayıp olduğu gibi aktarabilir. Çalışma süresini ölçen basit bir decorator örneği bu mekanizmayı net biçimde gösterir:
import functools
import time
def zaman_olcer(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
baslangic = time.perf_counter()
sonuc = func(*args, **kwargs)
gecen = time.perf_counter() - baslangic
print(f"{func.__name__} çalıştı: {gecen:.4f} saniye")
return sonuc
return wrapper
@zaman_olcer
def toplam_hesapla(a, b, carpan=1):
return (a + b) * carpan
toplam_hesapla(3, 5, carpan=2)
Bu örnekte toplam_hesapla fonksiyonu iki zorunlu ve bir opsiyonel parametre alsa da, wrapper hiçbirini tek tek tanımlamak zorunda kalmadan hepsini taşır. Kodun nasıl adım adım kurulduğunu şu şekilde özetleyebiliriz:
- Dış fonksiyon olan
zaman_olcertanımlanır ve parametre olarak sarmalanacak fonksiyonu (func) alır. - İçeride bir
wrapperfonksiyonu oluşturulur; bu fonksiyon*argsve**kwargsile gelebilecek her türlü konumsal ve anahtar kelimeli argümanı yakalar. wrapperiçinde orijinal fonksiyon, yakalanan argümanlar aynı şekilde açılarak (func(*args, **kwargs)) çağrılır.- Fonksiyonun ürettiği sonuç bir değişkende tutulup, ek işlem (burada süre ölçümü) yapıldıktan sonra çağırana döndürülür.
functools.wraps(func)dekoratörü eklenerek orijinal fonksiyonun adı, dokümantasyon dizesi gibi kimlik bilgileri korunur; aksi hâldetoplam_hesapla.__name__gibi ifadeler yanlışlıklawrapperdöndürür.
Bu yapı sayesinde aynı zaman_olcer decorator'ı, parametre sayısı ve isimleri tamamen farklı onlarca fonksiyona uygulanabilir. Decorator, loglama, önbellekleme veya yetkilendirme gibi kesişen ilgi alanlarında (cross-cutting concerns) neredeyse her zaman bu *args, **kwargs kalıbına dayanır; çünkü sarmalanan fonksiyonun imzasını tahmin etmek yerine onu olduğu gibi devretmek en güvenli yoldur.
Aşırı Kullanımın Okunabilirliği Bozduğu Durumlar

*args ve **kwargs her yerde kullanılabilir hâle geldiğinde, aslında çözdüğü problemden daha büyük bir problem yaratmaya başlar. Bir fonksiyon tanımını def kayit_olustur(*args, **kwargs): şeklinde yazmak teknik olarak çalışır, ama bu fonksiyonu çağıracak geliştirici hangi argümanların zorunlu, hangilerinin opsiyonel olduğunu, kaç tane parametre beklediğini ya da isimlerin ne olması gerektiğini fonksiyon gövdesini satır satır okumadan anlayamaz. Örneğin bir kullanıcı kayıt fonksiyonunda ad, soyad zorunlu iken yas opsiyonel olabilir; ama imza bunu hiçbir şekilde göstermez, bu bilgi yalnızca fonksiyonun içindeki kwargs.get("yas") satırlarında saklı kalır.
Bu belirsizlik, geliştirme araçlarının sunduğu desteği de devre dışı bırakır. Modern kod editörleri parametre isimlerini, tiplerini ve varsayılan değerlerini görerek otomatik tamamlama önerir; ama *args, **kwargs ile yazılmış bir fonksiyonda editör hangi anahtar kelimelerin geçerli olduğunu bilemez, dolayısıyla öneri listesi boş kalır veya anlamsızlaşır. Tip kontrol araçları da benzer şekilde işlevsiz hâle gelir; çünkü kwargs sözlüğünün içeriği statik analiz sırasında görünmez, bu yüzden yanlış bir anahtar veya yanlış tipte bir değer geçilse bile araç bunu önceden yakalayamaz.
Sorun en somut hâliyle hata mesajlarında ortaya çıkar. kayit_olustur(ad="Ayşe", soyad="Kaya", yass=28) gibi bir yazım hatası yapıldığında -yani yas yerine yanlışlıkla yass yazıldığında- Python bu hatayı fonksiyon çağrısı anında yakalamaz; çünkü **kwargs her anahtarı sessizce kabul eder. Hata, ancak fonksiyon içinde kwargs["yas"] çağrılırken KeyError olarak ortaya çıkar ve bu noktada hata mesajı, çağrının hangi satırda yapıldığından çok uzak bir yerde belirir. Geliştirici, gerçek hatanın kaynağını bulmak için çağrı zincirini geriye doğru takip etmek zorunda kalır; oysa açık parametreli bir fonksiyonda aynı hata, çağrı anında net bir TypeError: unexpected keyword argument mesajıyla anında görünür olurdu.
Açık Parametre Tanımlamanın Tercih Edilmesi Gereken Durumlar
Bir fonksiyonun arayüzü zamanla değişmeyecekse ve parametre sayısı makul bir sınırda kalıyorsa, *args, **kwargs yerine isimli parametreler ve varsayılan değerler kullanmak neredeyse her zaman daha sağlıklı bir tercihtir. Bu yaklaşım, fonksiyonun ne beklediğini imzaya bakar bakmaz anlaşılır kılar ve kodu okuyan kişinin fonksiyon gövdesine inmesine gerek bırakmaz. Gerekli olduğunda def olustur(ad, soyad, *, yas=None, sehir=None): gibi bir tanımda yıldız işaretinden sonra gelen yas ve sehir parametreleri keyword-only hâle gelir; yani çağıran kişi bunları mutlaka isimle belirtmek zorunda kalır, bu da olustur("Ayşe", "Kaya", 28) gibi hangi değerin neye ait olduğu belirsiz çağrıların önüne geçer.
Açık parametre tanımlamanın avantajları, özellikle birden fazla kişinin üzerinde çalıştığı veya uzun ömürlü olması beklenen kodlarda daha da belirginleşir:
- Fonksiyon imzası, dokümantasyon görevi görür; ayrıca açıklama yazmaya gerek kalmadan hangi argümanın zorunlu, hangisinin opsiyonel olduğu görünür.
- IDE'ler ve tip kontrol araçları parametre isimlerini, varsayılan değerleri ve tipleri tanıyarak gerçek zamanlı hata uyarısı ve otomatik tamamlama sunabilir.
- Yanlış argüman geçildiğinde hata, çağrı satırında ve anlaşılır bir mesajla anında ortaya çıkar; hata ayıklama süresi kısalır.
- Kodu daha sonra devralacak bir geliştirici, fonksiyonu değiştirmeden önce hangi davranışın hangi parametreye bağlı olduğunu kolayca çıkarabilir.
Bu prensip, fonksiyon tasarımının temel taşlarından biridir ve genellikle ilk öğrenildiğinde soyut kalır; gerçek anlamı ancak farklı senaryolarda kod yazarak, hata alarak ve o hatayı düzelterek oturur. birebir Python dersleri kapsamında bu tür tasarım kararları, öğrencinin yazdığı gerçek kod örnekleri üzerinden birebir geri bildirimle işlenir; böylece "ne zaman esnek, ne zaman açık" ayrımı ezber bir kural olmaktan çıkıp içselleştirilmiş bir alışkanlığa dönüşür.
Karar Tablosu: *args/**kwargs mi, Açık Parametre mi?
Bir fonksiyon tanımlarken hangi yolu seçeceğine karar vermek çoğu zaman "kural ezberlemek" değil, karşılaştığın senaryoyu doğru sınıflandırmak meselesidir. Aşağıdaki tablo, sık karşılaşılan durumları ve bu durumlarda hangi yaklaşımın daha sürdürülebilir olduğunu özetler.
| Durum | Önerilen Yaklaşım | Neden |
|---|---|---|
| Decorator veya wrapper fonksiyonu yazmak | *args ve **kwargs | Sarmalanan fonksiyonun imzası önceden bilinmez; esneklik zorunludur |
| Sabit ve az sayıda parametreli fonksiyon | Açık parametre | Parametre sayısı öngörülebilirken esnekliğe gerek yoktur, açıklık kazandırır |
| Çok takımlı veya uzun süre bakım gerektiren kod | Açık parametre (mümkün olduğunca) | IDE tamamlama ve kod okunabilirliği takım verimliliğini doğrudan etkiler |
| Opsiyonel ayarları çok olan yardımcı fonksiyon | **kwargs (dikkatli sınırlarla) | Zorunlu olmayan seçenekleri zorlamadan sunar, ama dokümantasyon şarttır |
| Üst sınıfın veya temel fonksiyonun imzasını koruma ihtiyacı | *args ve **kwargs ile yönlendirme (delegation) | Alt sınıf, üst sınıfın parametrelerini tekrar tanımlamadan iletebilir |
Tablodaki ayrım aslında tek bir soruya indirgenebilir: fonksiyonu çağıracak kişi ne bekliyor? Eğer çağıran taraf hangi parametrelerin geçerli olduğunu görmeden fonksiyonu güvenle kullanamıyorsa, esnek imza fayda değil risk üretiyor demektir. Tersine, fonksiyonun görevi zaten "aracılık etmek" (bir başka fonksiyona yönlendirmek) ise esnek imza doğru araçtır.
Python Öğreniminde Esnek Fonksiyonları Pekiştirme
args ve kwargs mantığı, ilk okumada anlaşılır görünse de gerçek anlamda oturması genellikle tek seferlik bir anlatımla değil, farklı bağlamlarda tekrar tekrar karşılaşmakla olur. Bir öğrenci decorator yazarken, bir başka gün API sarmalayıcısı kurarken, bir başka gün de sınıf kalıtımında üst yapıcıyı çağırırken aynı sözdizimini farklı amaçlarla kullandığında kavram gerçekten kalıcı hale gelir. Bu yüzden konuyu "anladım" demekle "içselleştirdim" demek arasındaki fark, uygulanan pratik miktarıyla doğru orantılıdır.
Berk Akademi'nin öğrenme ekosisteminde bu tekrarlı pekiştirme ihtiyacı göz önünde bulundurulur. Soru Avcısı ile öğrenciye günlük olarak sunulan akıllı alıştırmalar, esnek fonksiyon parametreleri gibi soyut görünen konuları küçük ve düzenli dozlarla tekrar ettirerek unutmayı engeller. Aynı şekilde kişiye özel öğrenci portalı üzerinden ilerleme takip edildiğinde, hangi konunun tekrar pratiğe ihtiyaç duyduğu netleşir; böylece *args ve **kwargs gibi kavramlar rastgele değil, hedefe yönelik biçimde tekrarlanır.
Kendi kendine pratik yaparken takılınan noktaları anlık olarak sormak isteyenler için birebir ilerleme daha hızlı sonuç verir. Bir sınıf projesinde neden esnek imzanın tercih edilmesi gerektiğini ya da bir hata mesajının kaynağını canlı olarak tartışmak isteyenler birebir Python dersleri kapsamında bu tür sorularını doğrudan bir eğitmenle çözebilir. Kendi hızında, kayıtlı derslerle ilerlemeyi tercih edenler için ise video eğitim formatı, konuyu istenildiği kadar tekrar izleme imkânı sunarak aynı pekiştirme ihtiyacına farklı bir yoldan cevap verir.
Sonuç olarak esnek parametre kullanımı, sözdizimini ezberlemekten çok "ne zaman gerekli, ne zaman gereksiz" sorusuna doğru refleksi geliştirmekle ilgilidir. Bu refleks de yalnızca kod yazarak, hata alarak ve o hatanın neden oluştuğunu anlayarak gelişir.
Sık Sorulan Sorular
*args ve **kwargs aynı fonksiyonda birlikte kullanılabilir mi?
Evet, ikisi aynı fonksiyon tanımında birlikte yer alabilir. Python'da sıralama önemlidir: önce sabit pozisyonel parametreler, sonra *args, ardından varsayılan değerli veya keyword-only parametreler, en sonda ise **kwargs gelmelidir.
*args ile gelen argümanlara sonradan isim vermek mümkün mü?
*args bir demet (tuple) olarak fonksiyona ulaşır ve elemanlarına yalnızca indeks üzerinden erişilir; kendiliğinden isim taşımaz. İsimlendirilmiş erişim istiyorsan bu argümanları fonksiyon içinde ayrı değişkenlere atayabilir veya baştan **kwargs tercih edebilirsin.
**kwargs sözlüğündeki anahtarların sırası garanti edilir mi?
**kwargs bir sözlük (dict) olarak fonksiyona geçer ve çağrı sırasında verilen anahtar-değer çiftlerinin ekleniş sırasını korur. Ancak fonksiyonun mantığını bu sıraya bağımlı kurmak yerine anahtar isimleriyle erişmek daha güvenli bir yaklaşımdır.
*args ve **kwargs kullanmak fonksiyonun çalışma hızını etkiler mi?
Bu mekanizma bir demet ve sözlük oluşturma işlemi içerdiği için açık parametrelere kıyasla çok küçük bir ek yük getirir. Ancak bu fark günlük geliştirme pratiğinde performans kararını etkileyecek düzeyde değildir; asıl belirleyici olması gereken kriter okunabilirlik ve bakım kolaylığıdır.
Keyword-only parametre nedir ve *args ile ilişkisi nedir?
Keyword-only parametre, yalnızca anahtar=değer biçiminde çağrılabilen, pozisyonel olarak verilemeyen parametredir. Fonksiyon tanımında *args'tan sonra gelen parametreler otomatik olarak keyword-only kabul edilir; bu sayede belirli ayarların yanlışlıkla sıralı biçimde geçilmesi engellenmiş olur.
Bir fonksiyonda hem açık parametreler hem *args nasıl birlikte tanımlanır?
Açık parametreler önce, *args daha sonra yazılır; örneğin def gonder(mesaj, *ekler): tanımında mesaj zorunlu bir parametre, ekler ise sıfır veya daha fazla ek argümanı toplayan esnek kısımdır. Bu düzen, fonksiyonun temel işini net tutarken opsiyonel genişlemeye de izin verir.
Decorator yazarken *args ve **kwargs kullanmazsam ne olur?
Sarmaladığın fonksiyon herhangi bir parametre bekliyorsa ve wrapper fonksiyonun bunları kabul edip iletmiyorsa, decorator yalnızca parametresiz fonksiyonlarla çalışır ve diğer tüm çağrılarda hata verir. Bu yüzden genel amaçlı bir decorator yazarken *args ve **kwargs neredeyse zorunlu bir güvenlik ağıdır.
*args ve **kwargs, Python'da esnekliği doğru yerde kullanmayı öğrenmenin önemli bir aşamasıdır; ancak bu esnekliğin ne zaman gerekli ne zaman gereksiz olduğunu ayırt etmek, fonksiyon yazma becerisinin olgunlaşmasıyla birlikte gelir. Konuyu daha fazla örnekle pekiştirmek ve seviyeni ölçmek isteyenler Python bilgi testi ile mevcut durumlarını değerlendirebilir.