← Back

Home › Hindi › *args और **kwargs Hindi में

*args और **kwargs — कितने भी arguments लेने वाले functions

🌐 यह page Hindi में है · Read the English functions guide →

*args**kwargsUnpackingDefault arguments

एक तारे और दो तारे का फर्क

*args अतिरिक्त positional arguments को एक tuple में बाँधता है। **kwargs अतिरिक्त keyword arguments को एक dict में। नाम कोई भी हो सकता है — *values भी चलेगा — पर convention यही है और हर Python programmer यही पढ़ने की उम्मीद करता है।

def show(*args, **kwargs):
    print("args  :", args, type(args).__name__)
    print("kwargs:", kwargs, type(kwargs).__name__)

show(1, 2, 3)
# args  : (1, 2, 3) tuple
# kwargs: {} dict

show(1, 2, name="Asha", city="Delhi")
# args  : (1, 2) tuple
# kwargs: {'name': 'Asha', 'city': 'Delhi'} dict

show()
# args  : () tuple      — खाली, error नहीं
# kwargs: {} dict

दोनों हमेशा भरे हुए नहीं होते। कोई अतिरिक्त argument न मिले तो args खाली tuple और kwargs खाली dict होता है — None नहीं। इसीलिए इन पर सीधा loop चलाना सुरक्षित है।

Parameters का सही क्रम

क्रम तय है और बदला नहीं जा सकता:

def f(positional, /, normal, *args, keyword_only, **kwargs):
    pass
#     ^^^^^^^^^^     ^^^^^^  ^^^^^^  ^^^^^^^^^^^^  ^^^^^^^^
#     सिर्फ positional  आम    बाकी सब  keyword ज़रूरी  बाकी सब

# व्यवहार में ज़्यादातर यही दिखता है
def log(message, *args, level="INFO", **kwargs):
    print(f"[{level}] {message}", args, kwargs)

log("saved", 42, True, level="DEBUG", user="asha")
# [DEBUG] saved (42, True) {'user': 'asha'}
# क्रम गलत — SyntaxError
def f(*args, normal, **kwargs):     # *args के बाद वाला keyword-only है,
    pass                            # ये सही है, पर default के बिना
                                    # हर call में उसे देना पड़ेगा

Unpacking — तारा उलटी दिशा में

यही तारे definition से बाहर भी काम करते हैं, बस उल्टा। Definition में बाँधते हैं, call में खोलते हैं:

nums = [1, 2, 3]
config = {"host": "localhost", "port": 8080}

total(*nums)              # total(1, 2, 3)
connect(**config)         # connect(host="localhost", port=8080)

# दोनों साथ
def connect(host, port, timeout=30, retries=3):
    ...
args = ["localhost", 8080]
extra = {"retries": 5}
connect(*args, **extra)   # connect("localhost", 8080, retries=5)

# unpacking definition में नहीं, list/tuple banane me bhi
first, *rest = [1, 2, 3, 4]     # first=1, rest=[2, 3, 4]
merged = [*nums, 4, 5]          # [1, 2, 3, 4, 5]
combined = {**config, "port": 9090}   # port override

आखिरी दो lines असली code में सबसे ज़्यादा काम आती हैं — एक list या dict की copy बनाकर एक चीज़ बदलना, मूल को छुए बिना।

असली use case — wrapper और decorator

*args, **kwargs का सबसे बड़ा use case तब है जब आप किसी और function को लपेट रहे हों और उसके signature की परवाह न करना चाहें:

import functools, time

def timed(fn):
    @functools.wraps(fn)
    def wrapper(*args, **kwargs):
        start = time.perf_counter()
        result = fn(*args, **kwargs)      # सब कुछ ज्यों का त्यों आगे
        print(f"{fn.__name__}: {time.perf_counter() - start:.4f}s")
        return result
    return wrapper

@timed
def fetch(url, retries=3, **opts):
    ...

fetch("https://x", retries=5, timeout=10)   # signature बदलने पर wrapper नहीं टूटेगा

functools.wraps भूल मत जाना — उसके बिना लपेटे गए function का नाम और docstring wrapper के हो जाते हैं, और debugging बहुत भ्रमित करने वाली बन जाती है।

आम गलतियाँ

def connect(host, port, **kwargs):
    ...

connect("localhost", 8080, timout=30)   # typo — कोई error नहीं!
# kwargs = {'timout': 30}, और timeout चुपचाप default पर रह गया

# बचाव: keyword-only parameters नाम स्पष्ट कर देते हैं
def connect(host, port, *, timeout=30, retries=3):
    ...
connect("localhost", 8080, timout=30)   # TypeError: unexpected keyword

Default arguments का trap

यह *args/**kwargs से सीधा जुड़ा नहीं, पर एक ही जगह आता है और सबसे ज़्यादा नुकसान करता है:

def add_item(item, box=[]):     # ❌ list एक ही बार बनती है,
    box.append(item)            #    definition के समय — हर call उसे साझा करता है
    return box

print(add_item(1))   # [1]
print(add_item(2))   # [1, 2]   — पिछली call की गंदगी!

def add_item(item, box=None):   # ✅
    if box is None:
        box = []
    box.append(item)
    return box

नियम याद रख लो: default value function के definition के समय एक बार evaluate होती है, हर call पर नहीं। इसलिए mutable default ([], {}, set()) हमेशा गलत है। None use करो और अंदर बनाओ।

क्या ये ज़रूरी है?

नहीं, और अक्सर ये नुकसानदेह है। तीन जगह ये सही है: wrapper और decorator, किसी और API को आगे बढ़ाना (जैसे logging), और CLI arguments जैसे अनिश्चित इनपुट। बाकी हर जगह साफ-साफ named parameters लिखो।

# ज़रूरत नहीं है
def add_all(*nums):
    return sum(nums)

# बेहतर — caller को पता चलता है क्या भेजना है
def add_all(nums: list[float]) -> float:
    return sum(nums)

# पर यहाँ सही है
def run(command, *args, env=None, **popen_kwargs):
    return subprocess.run([command, *args], env=env, **popen_kwargs)

🛠️ Practice करो (free, browser में)

पढ़ना काफी नहीं — यही bug खुद fix करके देखो। नीचे के problems browser में ही चलते हैं, कोई install नहीं, कोई login नहीं।

सारे free problems देखो →

अक्सर पूछे जाने वाले सवाल

*args और **kwargs क्या हैं?

*args अतिरिक्त positional arguments को एक tuple में बाँधता है और **kwargs अतिरिक्त keyword arguments को dict में। नाम कोई भी हो सकता है, पर यही convention है। दोनों खाली भी हो सकते हैं — तब () और {} मिलते हैं, None नहीं।

क्या args एक list है?

नहीं, tuple है। इसलिए args.append(x) पर AttributeError मिलेगा। Tuple immutable है, क्योंकि function को अपने arguments बदलने नहीं चाहिए। बदलना हो तो list(args) बनाओ।

Parameters का सही क्रम क्या है?

positional, फिर आम parameters, फिर *args, फिर keyword-only parameters, और अंत में **kwargs। ये क्रम तय है और बदला नहीं जा सकता।

Unpacking क्या है?

वही तारे उलटी दिशा में। Definition में args और kwargs बाँधते हैं; call में *list और **dict खोलते हैं। जैसे total(*[1,2,3]) यानी total(1,2,3)।

क्या हर function में इन्हें लगाना चाहिए?

नहीं। ये signature को बेमतलब बना देते हैं और typo चुपचाप kwargs में चला जाता है। सिर्फ wrapper, decorator, forwarding API और अनिश्चित इनपुट के लिए use करो — बाकी जगह named parameters लिखो।

आगे पढ़ो