Python'da *args parametresi fonksiyona verilen fazladan konumsal argümanları bir demet (tuple) olarak, **kwargs ise fazladan anahtar kelimeli argümanları bir sözlük olarak toplar. Parametre listesindeki tek başına / işaretinden önceki parametreler yalnızca konumla (positional-only), tek başına * işaretinden sonraki parametreler yalnızca adla (keyword-only) verilebilir. Çağrı tarafında ise *liste bir diziyi ayrı konumsal argümanlara, **sozluk bir sözlüğü ayrı anahtar kelimeli argümanlara açar.
Bu yazı, def ile fonksiyon tanımlama yazısının devamıdır ve parametre türlerini resmî Python belgelerindeki (Tutorial, Language Reference ve Programming FAQ) kurallarla anlatır: Argümanların parametrelere nasıl eşlendiğini, hangi çağrıların neden hata verdiğini, / ve * işaretlerini ne zaman kullanmanız gerektiğini ve argüman açmanın (unpacking) inceliklerini. Hata mesajlarının hepsi Python 3.15.2'de çalıştırılarak alındı.
Konumsal ve anahtar kelimeli argümanlar

Bir fonksiyonu çağırırken argümanları iki şekilde verebilirsiniz: sırayla (konumsal, positional) ya da ad=değer biçiminde (anahtar kelimeli, keyword). Hiçbir özel işaret kullanılmamış bir fonksiyonda her parametre iki şekilde de verilebilir. Varsayılan değeri olan parametreler çağrıda atlanabilir.
def siparis(urun, adet=1, boyut='orta', aciklama=''):
print(f'{adet} x {urun} ({boyut}) {aciklama}'.rstrip())
siparis('çay') # çıktı: 1 x çay (orta)
siparis(urun='kahve') # çıktı: 1 x kahve (orta)
siparis('kahve', 2) # çıktı: 2 x kahve (orta)
siparis('kahve', boyut='büyük', adet=3) # çıktı: 3 x kahve (büyük)
siparis('su', 6, 'küçük', 'soğuk') # çıktı: 6 x su (küçük) soğukTutorial'daki kurallar şöyle özetlenebilir: Bir çağrıda anahtar kelimeli argümanlar konumsal argümanlardan sonra gelmelidir. Verilen her anahtar kelime, fonksiyonun kabul ettiği bir parametre adına karşılık gelmelidir ve anahtar kelimelerin kendi aralarındaki sırası önemsizdir. Hiçbir parametre birden fazla değer alamaz. Bu kurallardan biri çiğnendiğinde ne olduğuna bakalım. Hataları tek tek yakalamak için küçük bir dene() yardımcısı yazdık; içindeki *args ve **kwargs yazımı bu yazının konusu, birkaç bölüm sonra ayrıntısıyla açıklanacak.
def dene(fonk, *args, **kwargs):
try:
fonk(*args, **kwargs)
except TypeError as e:
print(e)
def siparis(urun, adet=1):
pass
dene(siparis) # çıktı: siparis() missing 1 required positional argument: 'urun'
dene(siparis, 'çay', urun='su') # çıktı: siparis() got multiple values for argument 'urun'
dene(siparis, 'çay', renk='mavi') # çıktı: siparis() got an unexpected keyword argument 'renk'
dene(siparis, 'çay', 1, 2) # çıktı: siparis() takes from 1 to 2 positional arguments but 3 were givenBazı hatalar çalışma anında değil, kod derlenirken yakalanır. siparis(urun='çay', 2) yazarsanız dosya hiç çalışmaz ve SyntaxError: positional argument follows keyword argument alırsınız. Aynı anahtar kelimeyi iki kez vermek (siparis(adet=1, adet=2)) de SyntaxError: keyword argument repeated: adet hatasıdır.
Python argümanları parametrelere nasıl eşler?
Language Reference eşleme algoritmasını adım adım anlatır. Önce her parametre için boş bir "yuva" listesi oluşturulur. N tane konumsal argüman ilk N yuvaya yerleşir. Ardından her anahtar kelimeli argüman, adına karşılık gelen yuvaya konur; yuva zaten doluysa TypeError yükselir. Tüm argümanlar işlendikten sonra boş kalan yuvalar tanımdaki varsayılan değerlerle doldurulur. Varsayılanı olmayan boş bir yuva kalırsa yine TypeError alırsınız. Fazla konumsal argümanları *args, adı hiçbir parametreye uymayan anahtar kelimeleri **kwargs yakalar; bunlar yoksa fazlalık hatayla sonuçlanır. Yukarıdaki dört hata mesajı bu adımların her birine karşılık gelir.
*args: değişken sayıda konumsal argüman
Parametre listesinde *ad biçiminde bir parametre varsa, normal parametrelere sığmayan bütün konumsal argümanlar bir demet olarak bu ada atanır. Fazla argüman yoksa boş demet gelir. args yalnızca bir gelenektir; yıldızdan sonra istediğiniz adı yazabilirsiniz. Yıldızın kendisi önemlidir.
def toplam(*sayilar):
print(type(sayilar).__name__, sayilar)
return sum(sayilar)
print(toplam(1, 2, 3))
# çıktı: tuple (1, 2, 3)
# çıktı: 6
print(toplam())
# çıktı: tuple ()
# çıktı: 0Tutorial'ın belirttiği önemli bir kural: *args kendisinden sonra gelen bütün konumsal argümanları topladığı için, parametre listesinde ondan sonra yazılan parametreler yalnızca anahtar kelimeyle verilebilir. Bu özellik ayırıcı veya biçim gibi ayarları kalan argümanlardan ayırmak için çok kullanılır:
def birlestir(*parcalar, ayirici='/'):
return ayirici.join(parcalar)
print(birlestir('ev', 'iş', 'okul')) # çıktı: ev/iş/okul
print(birlestir('ev', 'iş', 'okul', ayirici=' | ')) # çıktı: ev | iş | okulbirlestir('ev', 'iş', ' | ') yazsaydınız ' | ' de bir parça sayılırdı. Yerleşik print() fonksiyonunun imzası da aynı mantıktadır: print(*objects, sep=' ', end='\n', file=None, flush=False). Bu yüzden sep ve end her zaman adla verilir.
**kwargs: değişken sayıda anahtar kelimeli argüman
Son parametre **ad biçimindeyse, tanımdaki hiçbir parametreye karşılık gelmeyen anahtar kelimeli argümanların hepsi bir sözlük olarak bu ada gelir. Language Reference, fazla anahtar kelime yoksa bu parametrenin her çağrıda yeni bir boş sözlük aldığını belirtir; varsayılan değer tuzağı burada yoktur. Tutorial ayrıca sözlükteki sıranın, argümanların çağrıda verildiği sırayla aynı olmasının garanti edildiğini söyler.
def profil(ad, **bilgiler):
print('Ad:', ad)
for anahtar, deger in bilgiler.items():
print(f' {anahtar}: {deger}')
print(type(bilgiler).__name__, len(bilgiler))
profil('Elif', sehir='İzmir', yas=29, meslek='mühendis')
# çıktı: Ad: Elif
# çıktı: sehir: İzmir
# çıktı: yas: 29
# çıktı: meslek: mühendis
# çıktı: dict 3
profil('Can')
# çıktı: Ad: Can
# çıktı: dict 0*args ve **kwargs birlikte kullanılabilir; tek kural *args'ın **kwargs'tan önce gelmesidir. **kwargs her zaman listenin son parametresidir: Ondan sonra bir parametre yazmak SyntaxError: parameters cannot follow var-keyword parameter verir.
Tek başına *: yalnızca anahtar kelimeyle verilen parametreler
Fazla konumsal argüman toplamak istemiyor, ama bazı parametrelerin mutlaka adla verilmesini istiyorsanız parametre listesine adsız tek bir * koyarsınız. Ondan sonraki parametreler keyword-only olur. Tutorial bunu, adların anlam taşıdığı ve tanımın adlarla daha anlaşılır olduğu durumlar ya da kullanıcıların argümanın konumuna güvenmesini engellemek istediğiniz durumlar için önerir. Örneğin dosya_kaydet(veri, True, False) çağrısında True'nun ne anlama geldiğini anlamak zordur; dosya_kaydet(veri, uzerine_yaz=True) ise kendini açıklar.
def dosya_kaydet(veri, *, uzerine_yaz=False, yedekle=True):
return f'veri={veri!r} uzerine_yaz={uzerine_yaz} yedekle={yedekle}'
print(dosya_kaydet('rapor', uzerine_yaz=True))
# çıktı: veri='rapor' uzerine_yaz=True yedekle=True
try:
dosya_kaydet('rapor', True)
except TypeError as e:
print(e)
# çıktı: dosya_kaydet() takes 1 positional argument but 2 were given
def baglan(*, sunucu):
return sunucu
try:
baglan()
except TypeError as e:
print(e)
# çıktı: baglan() missing 1 required keyword-only argument: 'sunucu'Keyword-only parametrelerin varsayılan değeri olmak zorunda değildir: baglan() örneğindeki sunucu zorunludur ama yalnızca adla verilebilir. * işaretinden sonra en az bir parametre gelmelidir; def f(a, *): yazımı SyntaxError: named parameters must follow bare * verir. Bir fonksiyonda * ve *args birlikte olamaz, çünkü ikisi de aynı sınırı çizer.
/: yalnızca konumla verilen parametreler

Python 3.8 ile gelen (PEP 570) / işareti tersini yapar: Ondan önceki parametreler yalnızca konumla verilebilir, adla verilemez. /'tan önce en az bir parametre olmalıdır. Tutorial'ın son örneği üç türü tek tanımda birleştirir; aşağıda aynı yapıyı Türkçe adlarla kurduk:
def dene(fonk, *args, **kwargs):
try:
print(fonk(*args, **kwargs))
except TypeError as e:
print('TypeError:', e)
def karma(konumsal, /, standart, *, anahtar):
return konumsal, standart, anahtar
dene(karma, 1, 2, anahtar=3) # çıktı: (1, 2, 3)
dene(karma, 1, standart=2, anahtar=3) # çıktı: (1, 2, 3)
dene(karma, 1, 2, 3) # çıktı: TypeError: karma() takes 2 positional arguments but 3 were given
dene(karma, konumsal=1, standart=2, anahtar=3)
# çıktı: TypeError: karma() got some positional-only arguments passed as keyword arguments: 'konumsal'Peki neden bir parametrenin adını kullanıcıdan saklamak isteyesiniz? Tutorial üç neden sayar. Parametre adının gerçek bir anlamı yoksa (örneğin bir matematik fonksiyonundaki x), argümanların sırasını zorunlu kılmak istiyorsanız ya da bazı konumsal parametrelerle birlikte istediğiniz anahtar kelimeyi kabul etmeniz gerekiyorsa. Ayrıca bir kütüphane yazıyorsanız, parametre adını ileride değiştirdiğinizde kullanıcıların kodu bozulmasın diye positional-only kullanmanız önerilir: Ad hiç dışarıya açılmadığı için değiştirmek güvenlidir.
Ad çakışmasını / ile çözmek
Tutorial'ın en öğretici örneklerinden biri, normal bir parametre ile **kwargs içindeki bir anahtarın aynı adı taşıdığı durumdur. name parametresi olan bir fonksiyona name anahtarlı bir sözlük açarsanız, anahtar her zaman ilk parametreye bağlanmaya çalışır ve çakışma olur. / eklendiğinde ise parametre adı dışarıya kapandığı için aynı ad **kwargs içinde serbestçe kullanılabilir:
def eski(ad, **ekstra):
return 'ad' in ekstra
try:
eski('Ali', **{'ad': 'Veli'})
except TypeError as e:
print(e) # çıktı: eski() got multiple values for argument 'ad'
def yeni(ad, /, **ekstra):
return 'ad' in ekstra
print(yeni('Ali', **{'ad': 'Veli'})) # çıktı: TrueYerleşik fonksiyonlardaki / ve *
Belgelerdeki yerleşik fonksiyon imzalarında bu işaretleri sık görürsünüz. sorted(iterable, /, *, key=None, reverse=False) imzası, dizinin yalnızca konumla, key ve reverse'ün yalnızca adla verilebileceğini söyler. len(obj, /) gibi C ile yazılmış bazı fonksiyonlar hiç anahtar kelime kabul etmez. Language Reference, CPython'da C ile yazılmış bazı fonksiyonların konumsal parametrelerinin belgede adı olsa bile gerçekte adı olmadığını açıkça belirtir.
print(sorted([3, 1, 2], reverse=True)) # çıktı: [3, 2, 1]
for kod in ('sorted([3, 1, 2], None, True)', 'len(obj=[1, 2])', 'divmod(a=7, b=2)'):
try:
eval(kod)
except TypeError as e:
print(e)
# çıktı: sorted expected 1 argument, got 3
# çıktı: len() takes no keyword arguments
# çıktı: divmod() takes no keyword argumentsParametre türleri ve sıralama kuralı
Bir tanımda bütün türleri kullanacaksanız sıra sabittir. Tutorial'daki şema def f(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2): biçimindedir; buna *args ve **kwargs eklendiğinde genel sıra şöyle olur:
def f(konumsal, /, standart, varsayilanli=1, *args, yalniz_ad, yalniz_ad2=2, **kwargs):
...| Tür | Tanımdaki yeri | Nasıl verilir | Örnek çağrı |
|---|---|---|---|
| Positional-only | / işaretinden önce | Yalnızca sırayla | f(1, ...) |
| Positional-or-keyword | / ile * arasında (varsayılan tür) | Sırayla ya da adla | f(1, 2) veya f(1, standart=2) |
| *args | Tek yıldızlı ad | Fazla konumsal argümanlar demet olur | f(1, 2, 3, 4) |
| Keyword-only | * veya *args sonrası | Yalnızca adla | f(..., yalniz_ad=5) |
| **kwargs | En sonda, çift yıldızlı ad | Fazla anahtar kelimeler sözlük olur | f(..., renk="mavi") |
Varsayılan değerlerle ilgili kısıt da unutulmamalı: / ile * arasındaki bölgede varsayılanı olan bir parametreden sonra varsayılanı olmayan bir parametre gelemez (SyntaxError: parameter without a default follows parameter with a default). Keyword-only bölgede ise bu kısıt yoktur, çünkü o parametreler zaten adla eşlenir.
Bir fonksiyonun imzasını incelemek
Elinizdeki bir fonksiyonun hangi parametreleri, hangi türde kabul ettiğini görmek için inspect.signature() kullanabilirsiniz; sonuç, tanımdaki parametre listesini varsayılan değerleriyle birlikte gösterir. Varsayılan değerler ayrıca fonksiyon nesnesinde de durur: Normal parametrelerinkiler __defaults__ demetinde, keyword-only parametrelerinkiler __kwdefaults__ sözlüğünde. Etkileşimli kabukta help(fonk) da aynı imzayı yazdırır.
import inspect
def f(a, b=2, *args, c, d=4, **kw):
pass
print(inspect.signature(f)) # çıktı: (a, b=2, *args, c, d=4, **kw)
print(f.__defaults__) # çıktı: (2,)
print(f.__kwdefaults__) # çıktı: {'d': 4}Çağrıda argüman açma: * ve **
Tersi durum da sık yaşanır: Argümanlar elinizde bir liste veya sözlük olarak durur, ama fonksiyon onları ayrı ayrı bekler. Çağrıda bir yinelenebilirin önüne * koyarsanız elemanları ayrı konumsal argümanlar olarak, bir sözlüğün önüne ** koyarsanız anahtar ve değerleri ayrı anahtar kelimeli argümanlar olarak gider. Python 3.5'ten beri (PEP 448) bir çağrıda istediğiniz kadar * ve ** açması kullanabilirsiniz.
aralik = [3, 6]
print(list(range(*aralik))) # çıktı: [3, 4, 5]
def adres(sokak, no, sehir):
return f'{sokak} No:{no}, {sehir}'
bilgi = {'sokak': 'Atatürk Cad.', 'no': 12, 'sehir': 'Ankara'}
print(adres(**bilgi)) # çıktı: Atatürk Cad. No:12, Ankara
print(adres(*['Gül Sk.', 3], sehir='Bursa')) # çıktı: Gül Sk. No:3, Bursa
print(*['a', 'b', 'c'], sep=' | ') # çıktı: a | b | c
def goster(**kw):
return kw
print(goster(**{'a': 1}, **{'b': 2}, c=3)) # çıktı: {'a': 1, 'b': 2, 'c': 3}Language Reference açma ile ilgili birkaç kenar durumu belirtir. ** ile açılan sözlüğün bütün anahtarları metin (str) olmalıdır; aksi hâlde TypeError: keywords must be strings alırsınız. Anahtarların geçerli bir Python tanımlayıcısı olması ise gerekmez: 'max-sıcaklık °C' gibi bir anahtar kabul edilir, ama hiçbir parametre adıyla eşleşemeyeceği için yalnızca **kwargs tarafından toplanabilir. İki farklı açmada aynı anahtar varsa ikinci değer reddedilir:
def goster(**kw):
return kw
print(goster(**{'max-sıcaklık °C': 30})) # çıktı: {'max-sıcaklık °C': 30}
try:
goster(**{1: 'bir'})
except TypeError as e:
print(e) # çıktı: keywords must be strings
try:
goster(**{'x': 1}, **{'x': 2})
except TypeError as e:
print(e)
# çıktı: __main__.goster() got multiple values for keyword argument 'x'Son mesajda fonksiyon adının __main__.goster() biçiminde, yani modül adıyla birlikte yazıldığına dikkat edin; Python 3.15.2 bu hata için nitelikli adı kullanıyor.
Değerlendirme sırası: *ifade anahtar kelimelerden önce işlenir
Belgelerdeki ince bir ayrıntı: *ifade yazımı çağrıda anahtar kelimeli argümanlardan sonra yazılsa bile, onlardan önce işlenir. Bu yüzden aşağıdaki ilk çağrı beklenmedik biçimde 2 1 yazar, ikincisi ise hata verir. Belgeler bu karışıklığın pratikte nadiren yaşandığını, çünkü anahtar kelimeler ile *ifade'nin aynı çağrıda pek kullanılmadığını da ekler.
def f(a, b):
print(a, b)
f(b=1, *(2,)) # çıktı: 2 1
try:
f(a=1, *(2,))
except TypeError as e:
print(e) # çıktı: f() got multiple values for argument 'a'Argümanları başka bir fonksiyona aktarmak
Programming FAQ, isteğe bağlı veya anahtar kelimeli parametreleri bir fonksiyondan diğerine aktarmanın yolunu şöyle anlatır: Tanımda * ve ** ile toplayın, çağrıda yine * ve ** ile açın. Bu kalıp, başka bir fonksiyonu sarmalayan yardımcıların ve decorator'ların temelidir; sarmalayıcı, asıl fonksiyonun imzasını bilmek zorunda kalmaz.
def kayitli_cagir(fonk, *args, **kwargs):
print('Çağrı:', fonk.__name__, args, kwargs)
return fonk(*args, **kwargs)
print(kayitli_cagir(round, 3.14159, ndigits=2))
# çıktı: Çağrı: round (3.14159,) {'ndigits': 2}
# çıktı: 3.14Sarmalayıcıyı decorator olarak yazmak ve asıl fonksiyonun adını, docstring'ini korumak için functools.wraps kullanmak decorator yazma rehberinde anlatılıyor. Aynı açma sözdizimi atamalarda da çalışır (ilk, *kalan = liste); bunun için tuple ve unpacking yazısına bakın.
Sık yapılan hatalar

- Anahtar kelimeden sonra konumsal argüman yazmak:
f(a=1, 2)derleme aşamasındaSyntaxErrorverir. - Aynı parametreye iki değer vermek:
f(1, a=2)gibi çağrılargot multiple values for argumenthatası üretir. - *args'tan sonraki parametreyi konumla vermeye çalışmak: O parametreler keyword-only'dir; değer
*argsdemetine gider. - **kwargs'a metin olmayan anahtar açmak:
f(**{1: 2})keywords must be stringshatası verir. - Yerleşik fonksiyona belgedeki adla argüman vermek:
len(obj=x)veyadivmod(a=7, b=2)çalışmaz; imzadaki/işaretine bakın. - Bayrak parametrelerini konumla vermek:
f(veri, True, False)okunmaz; bu tür parametreleri*ile keyword-only yapın. - args ve kwargs adlarını zorunlu sanmak: Önemli olan yıldızlardır;
*sayilar,**ayarlargibi anlamlı adlar seçebilirsiniz.
Sık Sorulan Sorular
*args ile **kwargs arasındaki fark nedir?
*args fazladan verilen konumsal argümanları bir demette, **kwargs fazladan verilen anahtar kelimeli argümanları bir sözlükte toplar. İkisi birlikte kullanılabilir; sıra her zaman *args, **kwargs şeklindedir.
Fonksiyon tanımındaki / ve * ne anlama gelir?
/'tan önceki parametreler yalnızca konumla, tek başına *'tan (veya *args'tan) sonraki parametreler yalnızca adla verilebilir. İkisi de isteğe bağlıdır; hiçbiri yoksa her parametre iki şekilde de verilebilir.
Bir listeyi fonksiyona ayrı argümanlar olarak nasıl veririm?
Çağrıda listenin önüne yıldız koyun: fonk(*liste). Sözlük için fonk(**sozluk) kullanın; anahtarlar parametre adlarıyla eşleşir.
kwargs sözlüğündeki sıra korunur mu?
Evet. Tutorial, **kwargs içindeki anahtarların çağrıda verildiği sırayla geleceğini garanti eder.
Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.
İlgili içerikler: Python öğrenme rehberi · def ile fonksiyon tanımlama · lambda, map ve sorted · Decorator yazma · Tuple ve unpacking · Sık hata mesajları