# Python में फ़ंक्शन: def, return, आर्गुमेंट, *args और **kwargs, lambda और टाइप एनोटेशन

URL: https://skillaria.top/hi/guides/python/funkcii-python

Python में फ़ंक्शन एक नाम वाला कोड-खंड है, जिसे def से घोषित किया जाता है, नाम और कोष्ठक से बुलाया जाता है और return से परिणाम लौटाया जाता है; बिना return के फ़ंक्शन None लौटाता है। आर्गुमेंट क्रम से या नाम से दिए जाते हैं, *args बाक़ी पोज़िशनल मानों को टपल में और **kwargs नाम वाले मानों को डिक्शनरी में इकट्ठा करता है, और lambda एक व्यंजन वाला छोटा बेनाम फ़ंक्शन है।

Python में फ़ंक्शन एक नाम वाला कोड-खंड है, जिसे अलग-अलग इनपुट के साथ कितनी भी बार बुलाया जा सकता है। इसे `def` से घोषित किया जाता है, पैरामीटर से मान लिए जाते हैं और `return` से परिणाम लौटाया जाता है। लंबी स्क्रिप्ट को समझने और जाँचने लायक चरणों में बाँटने का मुख्य तरीका फ़ंक्शन ही है।

## def से फ़ंक्शन घोषित करना

फ़ंक्शन की घोषणा `def` से शुरू होती है, फिर नाम, कोष्ठक में पैरामीटर और कोलन आते हैं। बॉडी चार स्पेस के इंडेंटेशन से लिखी जाती है — Python में इंडेंटेशन सजावट नहीं, सिंटैक्स का हिस्सा है।

```
def greet(name):
    """उपयोगकर्ता के लिए अभिवादन लौटाता है।"""
    return f"नमस्ते, {name}!"

print(greet("अनीता"))   # नमस्ते, अनीता!
```

शीर्षक के ठीक बाद तीन उद्धरण चिह्नों की स्ट्रिंग docstring है, यानी फ़ंक्शन का दस्तावेज़। उसे `help(greet)` और एडिटर के सुझाव दिखाते हैं। फ़ंक्शन के नाम PEP 8 के अनुसार snake_case में लिखे जाते हैं: `add_expense`, `get_rate`।

`def greet(name):` वाली पंक्ति को फ़ंक्शन का सिग्नेचर कहते हैं: नाम और पैरामीटर की सूची (और एनोटेशन, अगर हों)। सिग्नेचर देखकर पाठक समझ जाता है कि फ़ंक्शन कैसे बुलाना है, बिना बॉडी पढ़े।

## Python में return क्या करता है

`return` फ़ंक्शन को समाप्त करता है और बुलाने वाले को मान लौटाता है। `return` के बाद का कोड नहीं चलता। अगर `return` नहीं है, या बिना मान के लिखा है, तो फ़ंक्शन `None` लौटाता है।

```
def area(w, h):
    w * h          # परिणाम निकला, पर फेंक दिया गया

print(area(3, 4))  # None

def area(w, h):
    return w * h

print(area(3, 4))  # 12
```

छूटा हुआ `return` नए छात्रों की सबसे आम गलतियों में है: फ़ंक्शन «काम» करता दिखता है, पर `None` लौटाता है, और गड़बड़ी एक पंक्ति आगे जाकर दिखती है। एक से ज़्यादा मान भी लौटाए जा सकते हैं — असल में यह एक टपल होता है, जिसे आसानी से अनपैक किया जा सकता है:

```
def min_max(numbers):
    return min(numbers), max(numbers)

low, high = min_max([4, 1, 9])
print(low, high)   # 1 9
```

जल्दी `return` करने से अनावश्यक नेस्टिंग घटती है: पहले ख़ास स्थितियाँ निपटाएँ, फिर मुख्य तर्क लिखें।

```
def discount(price, is_member):
    if price  limit    # ग्लोबल को पढ़ना — ठीक है

def raise_limit():
    global limit
    limit = 2000             # global के बिना स्थानीय वेरिएबल बन जाता
```

व्यवहार में `global` से बचना बेहतर है: जो फ़ंक्शन बाहरी स्थिति बदलता है, उसे जाँचना कठिन होता है। भरोसेमंद तरीका है मान को आर्गुमेंट के रूप में लेना और परिणाम लौटाना।

## नेस्टेड फ़ंक्शन और क्लोज़र

फ़ंक्शन को दूसरे फ़ंक्शन के भीतर भी घोषित किया जा सकता है। भीतरी फ़ंक्शन बाहरी फ़ंक्शन के वेरिएबल देखता है, भले ही बाहरी फ़ंक्शन ख़त्म हो चुका हो — इसी को क्लोज़र कहते हैं। ऐसे वेरिएबल को बदलने के लिए `nonlocal` लिखा जाता है।

```
def make_counter():
    count = 0
    def counter():
        nonlocal count
        count += 1
        return count
    return counter

c = make_counter()
print(c(), c(), c())   # 1 2 3
```

क्लोज़र डेकोरेटर और फ़ंक्शन-फ़ैक्टरी की नींव हैं।

## फ़ंक्शन भी एक ऑब्जेक्ट है

Python में फ़ंक्शन एक साधारण ऑब्जेक्ट है: उसे वेरिएबल में रखा जा सकता है, दूसरे फ़ंक्शन को दिया जा सकता है, किसी फ़ंक्शन से लौटाया जा सकता है, डिक्शनरी में रखा जा सकता है। उसके गुण होते हैं: `__name__`, `__doc__`, `__defaults__`, `__annotations__`।

```
def double(x):
    return x * 2

f = double
print(f(5), f.__name__)                # 10 double
print(list(map(double, [1, 2, 3])))   # [2, 4, 6]
```

## Python में lambda: बेनाम फ़ंक्शन

Lambda एक छोटा फ़ंक्शन है, जिसका कोई नाम नहीं होता और बॉडी में सिर्फ़ एक व्यंजन होता है। व्यंजन का परिणाम अपने-आप लौटता है; `return` लिखना मना है।

```
square = lambda x: x ** 2
print(square(4))   # 16

expenses = [("कॉफ़ी", 250), ("टैक्सी", 600), ("भोजन", 450)]
expenses.sort(key=lambda e: e[1], reverse=True)
print(expenses)  # [('टैक्सी', 600), ('भोजन', 450), ('कॉफ़ी', 250)]

print(list(filter(lambda n: n % 2 == 0, range(10))))  # [0, 2, 4, 6, 8]
```

Lambda छोटे आर्गुमेंट के रूप में `sorted`, `max`, `map`, `filter` के साथ ठीक है। लेकिन जैसे ऊपर `square` को वेरिएबल में रखना PEP 8 के अनुसार अच्छा नहीं माना जाता: जिस फ़ंक्शन को नाम चाहिए, उसके लिए `def` लिखें — तब ट्रेसबैक में सामान्य `__name__` होगा और docstring की जगह भी।

|  | def | lambda |
| --- | --- | --- |

| नाम | है | नहीं (`<lambda>`) |

| बॉडी | कितने भी स्टेटमेंट | एक व्यंजन |

| return | स्पष्ट | अपने-आप |

| Docstring, एनोटेशन | हाँ | नहीं |

| कहाँ ठीक है | हर जगह | छोटी key या कॉलबैक |

## टाइप एनोटेशन: संकेत, जाँच नहीं

एनोटेशन बताते हैं कि पैरामीटर और परिणाम किस प्रकार के होने चाहिए। Python चलते समय इन्हें नहीं जाँचता: `x: int` वाला फ़ंक्शन भी स्ट्रिंग स्वीकार कर लेगा। जाँच बाहरी टूल करते हैं — mypy, pyright, ty — और एडिटर, जो चलाने से पहले ही गलती दिखा देता है।

```
def add_expense(title: str, amount: float, category: str = "अन्य") -> dict[str, object]:
    return {"title": title, "amount": amount, "category": category}

def area(w: float, h: float) -> float:
    w * h   # mypy: Missing return statement
```

इंस्टॉल किए बिना जाँच `uvx mypy .` से चलती है। ऊपर का उदाहरण दिखाता है कि एनोटेशन कितने काम के हैं: `-> float` के साथ छूटा `return` विश्लेषक तुरंत पकड़ लेता है।

Python 3.12 (PEP 695) से जेनेरिक फ़ंक्शन बिना `TypeVar` के लिखे जाते हैं: टाइप पैरामीटर वर्गाकार ब्रैकेट में आता है, और टाइप उपनाम शब्द `type` से घोषित होता है।

```
def first[T](xs: list[T]) -> T:
    return xs[0]

type Money = int | float
```

Python 3.14 (PEP 649) में एनोटेशन आलसी (lazy) हो गए: वे पहली बार इस्तेमाल होने पर मूल्यांकित होते हैं, इसलिए बाद में घोषित क्लास का नाम बिना उद्धरण चिह्न के लिखा जा सकता है, और `from __future__ import annotations` की ज़रूरत नहीं रही।

## «नहीं दिया गया» या «None दिया गया»: Python 3.15 का sentinel

डिफ़ॉल्ट `None` से यह पता नहीं चलता कि आर्गुमेंट नहीं दिया गया, या जानबूझकर `None` दिया गया। सालों तक इसका हल हाथ से बनाए गए मार्कर से निकाला जाता रहा:

```
_MISSING = object()

def get_rate(currency, default=_MISSING):
    rates = {"USD": 90.5}
    if currency in rates:
        return rates[currency]
    if default is _MISSING:
        raise KeyError(currency)
    return default
```

Python 3.15 में बिल्ट-इन फ़ंक्शन `sentinel` आया है (PEP 661): `MISSING = sentinel("MISSING")` एक अनूठा मार्कर बनाता है, जिसका repr साफ़ दिखता है, कॉपी करने पर भी वही रहता है, pickle से सेव हो सकता है, और `float | MISSING` जैसे एनोटेशन में काम आता है। पुराने वर्ज़न पर `object()` वाला तरीका चलता रहता है।

## फ़ंक्शन की आम गलतियाँ

- **return भूल गए** — फ़ंक्शन `None` लौटाता है।
- **कोष्ठक भूल गए** — `print(greet)` फ़ंक्शन-ऑब्जेक्ट छापेगा, कॉल का परिणाम नहीं।
- **बदले जा सकने वाला डिफ़ॉल्ट मान** — सभी कॉल में साझा लिस्ट।
- **आर्गुमेंट की गलत संख्या** — `TypeError: greet() missing 1 required positional argument: 'name'`।
- **बिल्ट-इन नाम जैसा फ़ंक्शन नाम** — `list` या `sum` नाम का फ़ंक्शन बिल्ट-इन को ढक देगा।

## निष्कर्ष

Python में फ़ंक्शन `def` से बनते हैं, परिणाम `return` से लौटाते हैं और आर्गुमेंट क्रम से या नाम से लेते हैं। `*args` और `**kwargs` लचीलापन देते हैं, `/` और `*` कॉल को सख़्त बनाते हैं, lambda एक बार के फ़ंक्शन को छोटा करता है, और टाइप एनोटेशन mypy के साथ मिलकर गलतियाँ चलाने से पहले पकड़ते हैं। कोर्स में यह विषय व्यवहार में सिखाया जाता है: ख़र्च ट्रैकर को एनोटेशन वाले फ़ंक्शनों में बाँटा जाता है और mypy से जाँचा जाता है।

## FAQ

**पैरामीटर और आर्गुमेंट में क्या फ़र्क है?**

पैरामीटर फ़ंक्शन की घोषणा में दिया गया नाम है, और आर्गुमेंट कॉल के समय दिया गया असली मान। def greet(name) में name पैरामीटर है, और greet("अनीता") में "अनीता" आर्गुमेंट।

**क्या फ़ंक्शन को घोषित होने से पहले बुलाया जा सकता है?**

मॉड्यूल स्तर पर नहीं: def वाली पंक्ति कॉल से पहले चलनी चाहिए, वरना NameError आएगा। लेकिन किसी दूसरे फ़ंक्शन के भीतर बाद में घोषित फ़ंक्शन बुलाया जा सकता है, बशर्ते कॉल तब हो जब वह घोषित हो चुका हो।

**फ़ंक्शन एक से ज़्यादा मान कैसे लौटाता है?**

औपचारिक रूप से एक ही मान, पर वह मान टपल हो सकता है: return a, b दो तत्वों का टपल लौटाता है, जिसे x, y = f() से अनपैक करते हैं।

**क्या टाइप एनोटेशन लिखना ज़रूरी है?**

नहीं, Python इनके बिना भी चलता है। पर दूसरों द्वारा पढ़े जाने वाले कोड में एनोटेशन रखरखाव आसान करते हैं और mypy या pyright को चलाने से पहले गलतियाँ पकड़ने देते हैं।

**क्या lambda में if लिखा जा सकता है?**

सिर्फ़ शर्तीय व्यंजन: lambda x: "सम" if x % 2 == 0 else "विषम"। lambda के भीतर स्टेटमेंट, लूप और असाइनमेंट मान्य नहीं हैं।


---
Source: Skillaria.Top (https://skillaria.top)
