Exercises — ` - args` and ` - kwargs` — flexible argument passing
1.2.29 · D4· Coding › Introduction to Programming (Python) › [[1.2.29- argsand- kwargs— flexible argument passing|- argsand- kwargs— flexible argument passing]]
Ek quick refresher — bas ek rule jo tumhe sach mein yaad rakhna hai:

Level 1 — Recognition
Yahan tumhe bas decide karna hai ki ek naam kis type ka value hold karta hai aur ek value kis box mein jaati hai.
Exercise 1.1
args ki exact value aur Python type batao.
def f(*args):
return args
print(f(7, 8, 9))Recall Solution 1.1
Definition mein star saare positional arguments ko ek tuple mein collect karta hai. Teen values aati hain, toh:
- Output:
(7, 8, 9) - Type: ek tuple (round brackets, immutable).
Humne kya kiya: star ko "leftovers gather karo" ki tarah padha. Kyun:
*argsse pehle koi named parameter nahi hai, toh har value ek leftover hai.
Exercise 1.2
Yahan kwargs kya hai — value aur type?
def g(**kwargs):
return kwargs
print(g(x=1, y=2))Recall Solution 1.2
** key=value pairs ko ek dict mein collect karta hai:
- Output:
{'x': 1, 'y': 2} - Type: ek dict (curly braces, key→value).
Exercise 1.3
In mein se kaun se legal function headers hain? Har ek ko mark karo.
# A
def a(*args, **kwargs): pass
# B
def b(**kwargs, *args): pass
# C
def c(x, *args): pass
# D
def d(**kwargs): passRecall Solution 1.3
- A — legal.
*argska**kwargsse pehle aana correct order hai. - B — SyntaxError.
**kwargslast parameter hona chahiye; catch-all dict ke baad kuch nahi aa sakta. - C — legal. Ek named positional ke baad
*args. - D — legal.
**kwargsakela bhi theek hai. B kyun fail hota hai: jab ek aisa box ho jo saare remaining keywords absorb kar le, toh uske baad kuch bhi catch karne ke liye kuch bachta hi nahi.
Level 2 — Application
Ab tum kai arguments ko correct box mein route karte ho aur ek result compute karte ho.
Exercise 2.1
Poora return value predict karo.
def f(a, *args, **kwargs):
return a, args, kwargs
print(f(1, 2, 3, x=9, y=10))Recall Solution 2.1
Slots ko left se right fill karo:
apehla positional leta hai →1.*argsbaaki positionals sweep karta hai →(2, 3).**kwargsaise keywords sweep karta hai jinका koi named slot nahi →{'x': 9, 'y': 10}.- Output:
(1, (2, 3), {'x': 9, 'y': 10})
Exercise 2.2
Ek function product likho jo kisi bhi number of arguments ko multiply kare, aur koi argument na ho toh 1 return kare. Phir product(2, 3, 4) aur product() do.
Recall Solution 2.2
def product(*nums):
total = 1
for x in nums:
total *= x
return totalproduct(2, 3, 4)→2*3*4=24.product()→numsempty tuple()hai, loop kabhi nahi chalta, toh startingtotal=1return hota hai. 1 se kyun shuru karein?1multiplicative identity hai — isse multiply karna kuch nahi badalta, toh ye correct "empty product" hai, bilkul waise jaise0correct empty sum hai.
Exercise 2.3
Call-site unpacking use karo taaki add ek list se aur ek dict se kaam kare.
def add(a, b, c):
return a + b + c
nums = [5, 6, 7]
opts = {'a': 10, 'b': 20, 'c': 30}
# fill in with * and **Recall Solution 2.3
add(*nums) # spreads to add(5, 6, 7) -> 18
add(**opts) # spreads to add(a=10, b=20, c=30) -> 60add(*nums)→18.add(**opts)→60. Yahan star kya karta hai (opposite direction): ek call mein ye ek collection ko wapas alag-alag arguments mein spread karta hai, bilkul mirror image of how it gathered them in a definition.
Level 3 — Analysis
Yahan tumhe reason karna hoga ki kyun ek call succeed, fail, ya override hoti hai.
Exercise 3.1
Explain karo kyun pehli call kaam karti hai aur doosri error raise karti hai.
def f(a, b):
return a + b
f(*[1, 2]) # call 1
f(*[1, 2, 3]) # call 2Recall Solution 3.1
- Call 1:
*[1, 2]exactly do positionals mein spread hota hai →f(1, 2)→3. ✅ - Call 2:
*[1, 2, 3]teen positionals mein spread hota hai, lekinfke paas sirfaaurbslots hain. Extra3catch karne ke liye koi*argsnahi hai, toh PythonTypeError: f() takes 2 positional arguments but 3 were givenraise karta hai. Analysis: unpacking count ko maaf nahi karta — ye bas itne arguments hand over karta hai. Receiving header ko unhe hold karne mein capable hona chahiye.
Exercise 3.2
final kya hai aur kyun?
defaults = {'color': 'red', 'size': 'M', 'qty': 1}
user = {'size': 'L', 'qty': 3}
final = {**defaults, **user}Recall Solution 3.2
final={'color': 'red', 'size': 'L', 'qty': 3}. Kyun:{**a, **b}pehleako pour karta hai, phirbko. Jab ek key dono mein hoti hai, toh baad wali value jeet jaati hai kyunki wo baad mein same slot mein likhi jaati hai. Tohuserkasize='L'aurqty=3defaultsko override karta hai, jabkicolor(sirfdefaultsmein) untouched rehta hai.
Exercise 3.3
Dhyan se trace karo. Ye kya print karta hai?
def f(a, b=100, *args):
return a, b, args
print(f(1))
print(f(1, 2, 3, 4))Recall Solution 3.3
f(1):a=1,bapna default100use karta hai,args=(). Output:(1, 100, ()).f(1, 2, 3, 4):a=1,b=2(default override hota hai), phir leftovers3, 4args=(3, 4)mein sweep hote hain. Output:(1, 2, (3, 4)). Analysis: ek default parameter pehle next positional se fill hota hai; sirf baad mein jab har named slot satisfy ho jaata hai tab*argscollect karna shuru karta hai.
Level 4 — Synthesis
Ab tum reusable tools banate ho jo aisi arguments forward karte hain jo unhe samajh nahi aate.
Exercise 4.1
call_twice(func, *args, **kwargs) likho jo func ko same arguments ke saath do baar call kare aur dono results ek tuple mein return kare. pow ke saath test karo.
Recall Solution 4.1
def call_twice(func, *args, **kwargs):
return func(*args, **kwargs), func(*args, **kwargs)
call_twice(pow, 2, 3) # (8, 8)- Output:
(8, 8). Ye kisi bhi function ke liye kyun kaam karta hai:funcke baad jo bhi aata hai use hum*args, **kwargsse catch karte hain, phirfunc(*args, **kwargs)se wapas spread karte hain.call_twiceko kabhipowki real signature jaanne ki zaroorat nahi.
Exercise 4.2
Ek debug wrapper (ek mini-decorator) likho jo print kare ki function ko kis arguments ke saath call kiya gaya, phir uska result unchanged return kare. Ek chhote se mul pe test karo.
Recall Solution 4.2
def debug(func):
def wrapper(*args, **kwargs):
print("call", func.__name__, args, kwargs)
result = func(*args, **kwargs)
print("->", result)
return result
return wrapper
@debug
def mul(a, b):
return a * b
mul(6, 7) # prints, then returns 42mul(6, 7)ka return value →42.- Print hoga:
call mul (6, 7) {}phir-> 42.*args, **kwargskyun zaroori hai: wrapper ko koi bhi signature accept karni chahiye jo decorated function ki ho sakti hai, toh wo sab kuch generically catch karta hai aur faithfully forward karta hai.
Exercise 4.3
merge_settings(base, **overrides) likho jo ek nayi dict return kare: base jisme overrides top pe applied hon (base ko mutate kiye bina). Ise test karo.
Recall Solution 4.3
def merge_settings(base, **overrides):
return {**base, **overrides}
cfg = {'debug': False, 'level': 1}
merge_settings(cfg, level=5, verbose=True)
# {'debug': False, 'level': 5, 'verbose': True}- Output:
{'debug': False, 'level': 5, 'verbose': True}. cfgunchanged rehta hai (abhi bhi{'debug': False, 'level': 1}) kyunki{**base, ...}ek nayi dict banata hai. Kyun:**overridescaller keywords ko ek dict mein catch karta hai, aur merge literal overrides ko last mein likhta hai, toh wo jeet jaate hain — exactly "user beats defaults" pattern.
Level 5 — Mastery
Mixed, tricky rules ke under poora reasoning.
Exercise 5.1
Output predict karo. Keyword-only parameter sep ko dhyan se dekho.
def join_all(*parts, sep="-"):
return sep.join(parts)
print(join_all("a", "b", "c"))
print(join_all("a", "b", "c", sep="/"))Recall Solution 5.1
sep *args ke baad baithta hai, toh ye keyword-only ban jaata hai — tum isse sirf naam se set kar sakte ho.
join_all("a", "b", "c"):parts=("a","b","c"),sepapna default"-"rakhta hai →"a-b-c".join_all("a", "b", "c", sep="/"): same parts,sep="/"→"a/b/c". Kyun keyword-only: kyunki*partslaalach se har positional kha jaata hai,septak pahunchne ka ek hi tarika hai — use naam se bulao — ye ek deliberate, useful design hai.
Exercise 5.2
Ye error raise karta hai. Exactly batao kaun si aur kyun, phir ise fix karo taaki x keyword-only ban jaaye.
def f(*args, x):
return args, x
f(1, 2, 3)Recall Solution 5.2
f(1, 2, 3)→TypeError: f() missing 1 required keyword-only argument: 'x'. Kyun:*argske baadxkeyword-only hai aur uska koi default nahi, toh ye naam se required hai. Teen positionalsargs=(1,2,3)fill karte hain lekin koix=...supply nahi karta.- Fix (ise optional banao):
def f(*args, x=0):
return args, x
f(1, 2, 3) # ((1, 2, 3), 0)
f(1, 2, x=9) # ((1, 2), 9)f(1, 2, 3)→((1, 2, 3), 0);f(1, 2, x=9)→((1, 2), 9).
Exercise 5.3
Full trace — sab kuch combine karo. Program kya print karta hai?
def report(title, *rows, sep=" | ", **meta):
line = sep.join(str(r) for r in rows)
return title, line, meta
print(report("Scores", 10, 20, 30, sep=", ", author="Ravi", year=2024))Recall Solution 5.3
Har argument ko route karo:
title="Scores"(pehla positional).*rowsremaining positionals sweep karta hai →(10, 20, 30).sepexplicitly naam se diya gaya →", "(keyword-only).**metaleftover keywords catch karta hai →{'author': 'Ravi', 'year': 2024}.line="10, 20, 30".- Output:
('Scores', '10, 20, 30', {'author': 'Ravi', 'year': 2024}). Ye poori picture kyun hai: ye poora legal order exercise karta hai — positional,*args, keyword-only,**kwargs— sab ek hi call mein. Neeche figure dekho jo routing trace karta hai.

Exercise 5.4
{**a, **b} conflict + unpacking count. Dono lines predict karo.
a = {'p': 1, 'q': 2}
b = {'q': 9, 'r': 3}
print({**a, **b})
def g(p, q, r):
return p + q + r
print(g(**{**a, **b}))Recall Solution 5.4
- Merge: pehle
a, phirb; conflictingq→bjeet jaata hai. Result{'p': 1, 'q': 9, 'r': 3}. g(**{...})us dict kog(p=1, q=9, r=3)ki tarah spread karta hai →1 + 9 + 3=13.- Outputs:
{'p': 1, 'q': 9, 'r': 3}phir13.
Connections
- Functions and Parameters — wo base jis par har exercise banti hai.
- Default Arguments — L3 aur L5 mein use hua.
- Tuples —
*argskya yield karta hai. - Dictionaries —
**kwargskya yield karta hai; L3/L5 mein merge rules. - Decorators — L4 wrapper pattern.
- Unpacking Assignment — assignments mein same star idea.