1.2.29 · D5 · HinglishIntroduction to Programming (Python)

Question bank` - args` and ` - kwargs` — flexible argument passing

2,151 words10 min read↑ Read in English

1.2.29 · D5 · Coding › Introduction to Programming (Python) › [[1.2.29 - args and - kwargs — flexible argument passing| - args and - kwargs — flexible argument passing]]

Shuru karne se pehle, teen anchors taaki koi symbol unearned na lage:

Har trap ke peeche ki picture

Traps pe attack karne se pehle, yeh routing diagram memory mein burn kar lo. Jab Python ek call receive karta hai, toh woh arguments ko left-to-right teen bins mein sort karta hai: pehle named slots, phir *args tuple baaki bache positionals ko sweep karta hai, phir **kwargs dict baaki bache keywords ko sweep karta hai.

Figure — ` - args` and ` - kwargs` — flexible argument passing

Arrows dekho: burnt-orange values tuple mein flow karte hain, teal name=value pairs dict mein flow karte hain, aur sirf plum-labelled named slots pehle fill hote hain. Neeche ka har trap basically yahi diagram hai jisme ek arrow wahan chala gaya jahan tumne expect nahi kiya tha.


True or false — justify karo

Star positionals ko ek list mein collect karta hai.
False. *args ek tuple produce karta hai, jo immutable hai — tum args.append(x) nahi kar sakte; agar mutate karna ho toh pehle list(args) karna padega.
**kwargs pairs ka ek tuple produce karta hai.
False. Yeh ek dict produce karta hai, keyword names se keyed, isliye kwargs["x"] kaam karta hai aur kwargs.items() (name, value) pairs deta hai.
args aur kwargs naam wo keywords hain jo Python require karta hai.
False. Sirf * aur ** meaning carry karte hain; def f(*stuff, **options) bilkul valid hai — args/kwargs sirf readability ke liye convention hain.
def f(a, *args, b) mein b ek normal positional parameter ban jaata hai.
False. *args ke baad aane wali koi bhi cheez keyword-only ban jaati hai: b ko b=... ke roop mein pass karna padega, kyunki *args pehle hi har bacha hua positional value nigl jaata hai.
Tum def f(**kwargs, *args) likh sakte ho.
False — yeh ek SyntaxError hai. Ek catch-all dict last parameter hona chahiye; koi bhi cheez uss cheez ke baad nahi aa sakti jo saare baake keywords absorb kar leti hai.
add(nums) call karna jahan nums=[1,2,3] hai, woh add(*nums) ke barabar hai.
False. add(nums) list ko ek argument ke roop mein pass karta hai; add(*nums) ise teen alag positional arguments mein spread karta hai. * bhoolna ek classic bug hai.
{**a, **b} mein, agar dono dicts ek key share karti hain, toh a jeet jaata hai.
False. Baad wala spread jeetta hai, isliye b shared keys pe a ko override karta hai — dict literals left se right evaluate hote hain, aur har key pichli wali ko overwrite kar deti hai.
*args aur **kwargs sirf function definition mein hi appear ho sakte hain.
False. Dono call site pe bhi kaam karte hain taaki ek sequence/dict ko alag arguments mein unpack kiya ja sake — woh mirror-image use aadhi power hai.
def f(*args) wali function crash ho jaayegi agar zero arguments ke saath call ki jaaye.
False. args simply empty tuple () ban jaata hai; koi error nahi. Hamesha is empty case ke against division/indexing guard karo.

The name-collision trap (worked out)

Ek subtle case jis pe log trip karte hain: kya ek keyword argument *args se already caught value ke saath "collide" kar sakta hai? Jawaab firmly nahi hai — woh alag bins mein rehte hain, aur neeche ka code exactly isliye dikhata hai. Ise upar ke routing diagram ke against trace karo.


Error dhundho

def f(a, **kwargs, b=2): ...
**kwargs last nahi hai — SyntaxError. Ise end mein le jaao: def f(a, b=2, **kwargs).
def total(*args): return args + 10
args ek tuple hai, aur tuple + int ek TypeError hai. Tumhara matlab tha sum(args) + 10 — tumhe pehle tuple ko ek number mein reduce karna hoga.
config = {"lr": 0.1}; train(*config)
Ek dict pe ek star use karne se sirf uski keys positionals ke roop mein spread hoti hain (train("lr")), jo almost kabhi bhi tumhara matlab nahi hota. Key=value pairs spread karne ke liye train(**config) use karo.
def g(*args, **kwargs, extra): ...
**kwargs ke baad koi parameter illegal hai — SyntaxError. Keyword-only params *args aur **kwargs ke beech mein hone chahiye, jaise def g(*args, extra, **kwargs).
log(func, *args, **kwargs); func(args, kwargs)
Re-call stars drop kar deta hai, isliye func spread-out arguments ki jagah ek tuple aur ek dict do positional values ke roop mein receive karta hai. Sahi forwarding hai func(*args, **kwargs).
def h(a, *args): return a; h(*[])
h(*[]) ek empty list spread karta hai, isliye kuch bhi required a fill nahi karta → TypeError: missing 1 required positional argument. Empty sequence pe * zero arguments supply karta hai.
def m(**kwargs): return kwargs[0]
kwargs ek dict hai jo strings se keyed hai, integer-indexed sequence nahi; kwargs[0] KeyError raise karta hai. kwargs["name"] use karo ya kwargs.items() iterate karo.

Why questions

**kwargs hamesha definition mein last kyun hona chahiye?
Yeh har leftover keyword ke liye ek catch-all hai; agar kuch iske baad aata, toh woh parameter kabhi value receive nahi kar sakta — greedy dict pehle hi use absorb kar chuka hota. Isliye grammar ise forbid karta hai.
args list ki jagah tuple ke roop mein kyun waapas aata hai?
Tuples immutable hote hain, signal karte hue "yeh ek fixed snapshot hai jo pass kiya gaya tha" aur captured arguments ko safely hashable/unchangeable banate hain — Python jaan-boojhkar tumhe ek read-only bundle deta hai.
Wahi * symbol pack aur unpack dono kyun karta hai?
Kyunki packing (def) aur unpacking (call) exact inverses hain — ek many-into-one gather karta hai, doosra one-into-many split karta hai. Symbol reuse karne se f(*x) ka round-trip jahan def f(*x) visually symmetric dikhta hai.
*args ke baad parameters keyword-only kyun ban jaate hain?
Jab *args har bacha hua positional value khaana shuru karta hai, toh baad ke parameters ke liye koi positional slot nahi bachta — isliye unhe reach karne ka ek hi tarika hai naam se.
*args, **kwargs decorators mein calls forward karne ka standard tarika kyun hai?
Ek decorator ek unknown function wrap karta hai, isliye woh us function ke parameters naam nahi le sakta; *args, **kwargs se sab kuch catch karke func(*args, **kwargs) se re-spread karne se koi bhi signature untouched forward ho jaati hai.
def f(a, b, *args) mein phir bhi a aur b kyun required hain?
*args sirf leftover positionals collect karta hai named ones ke satisfy hone ke baad. Required a, b pehle fill hote hain; sirf tab surplus args mein flow karta hai.
{**a, **b} ko dict merge karne ke liye a.update(b) call karne se kyun prefer karte hain?
Star form bina a ko mutate kiye ek naya dict banata hai; update a ko in place change karta hai. Override rule same hai (baad wala jeetta hai), different side effect.

Edge cases

Neeche ke traps sab boundaries pe rehte hain — empty inputs, bare stars, mixed iterables. Figure char traps ko side by side walk karta hai taaki tum memory-model outcome dekh sako instead of apne head mein simulate karne ke.

Figure — ` - args` and ` - kwargs` — flexible argument passing
args kya hota hai jab tum f() call karte ho jahan def f(*args) hai?
Empty tuple ()None nahi, error nahi — ek empty container jisko tum safely loop kar sakte ho (zero times).
f(*[42]) kya bind karta hai agar def f(x) ho?
Ek ek-element unpack exactly single positional x=42 fill karta hai. Unpacking kisi bhi length ke liye kaam karta hai, ek aur zero bhi shaamil.
Kya def f(*args, **kwargs) bilkul koi bhi argument nahi hone pe bhi call accept kar sakta hai?
Haan. args () ban jaata hai aur kwargs {} ban jaata hai — sabse permissive signature possible, kuch bhi accept karta hai including kuch bhi nahi.
f(1, 2, a=3) ke saath kya hota hai jab def f(a, *args) ho?
TypeError: a positionally 1 se fill ho jaata hai, phir a=3 use dobara fill karne ki koshish karta hai — ek parameter position aur keyword dono se bind nahi ho sakta.
Agar def f(a, *, b) (bare star) ho, toh akela * kya karta hai?
Yeh koi bhi value capture nahi karta lekin iske baad aane wali har cheez keyword-only bana deta hai: b ko b=... ke roop mein dena padega, aur f(1, 2) ek error hai.
def f(a, *args, b, **kwargs) minimum kya demand karta hai?
a (positional) aur b (keyword-only, kyunki yeh *args ke baad baith ta hai) dono required hain; args aur kwargs empty ho sakte hain. Isliye f(1, b=2) minimum valid call hai.
Kya f(*gen) unpack karna kaam karta hai agar gen ek generator ho, list nahi?
Haan — koi bhi iterable * se spread ho sakta hai, generators, strings, aur sets bhi (sets ke liye order arbitrary hai). Star iterable ko position by position consume karta hai.


Connections

  • Functions and Parameters — parameter rules jinhe yeh traps stress-test karte hain.
  • Default Arguments*args ke baad keyword-only slots ke saath interact karte hain.
  • Tuples — woh *args kya banta hai (immutable → kai traps).
  • Dictionaries — woh **kwargs kya banta hai.
  • Decorators — "Spot the error" mein forwarding traps.
  • Unpacking Assignment — same star idea function calls ke bahar.