Question bank — ` - args` and ` - kwargs` — flexible argument passing
1.2.29 · D5· Coding › Introduction to Programming (Python) › [[1.2.29- argsand- kwargs— flexible argument passing|- argsand- 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.

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.
*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.
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.
* 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.
*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.
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.
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.
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.
def f(*args) wali function crash ho jaayegi agar zero arguments ke saath call ki jaaye.
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)
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)
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?
args list ki jagah tuple ke roop mein kyun waapas aata hai?
Wahi * symbol pack aur unpack dono kyun karta hai?
f(*x) ka round-trip jahan def f(*x) visually symmetric dikhta hai.*args ke baad parameters keyword-only kyun ban jaate hain?
*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?
*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?
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.

args kya hota hai jab tum f() call karte ho jahan def f(*args) hai?
()। 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?
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?
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?
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?
* 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 —
*argske baad keyword-only slots ke saath interact karte hain. - Tuples — woh
*argskya banta hai (immutable → kai traps). - Dictionaries — woh
**kwargskya banta hai. - Decorators — "Spot the error" mein forwarding traps.
- Unpacking Assignment — same star idea function calls ke bahar.