अध्याय 19

फ़ंक्शंस — एक निर्णय, एक नाम

def से फ़ंक्शन लिखना, return और print का अंतर, शुरुआत में गार्ड से किनारे के मामलों को संभालना, और डॉकस्ट्रिंग्स।

35 मिनटPython 3.12
  1. 1समस्या
  2. 2समझें
  3. 3उदाहरण
  4. 4अनुमान
  5. 5स्वयं करें
  6. 6चुनौती

वह समस्या जिसे हम हल कर रहे हैं

दो समूहों को उनके औसत अंक की आवश्यकता है:

python
marks_a = [72, 45]
marks_b = [90, 33, 61]

print(round(sum(marks_a) / len(marks_a), 2))
print(round(sum(marks_b) / len(marks_b), 2))
text
58.5
61.33

दोनों पंक्तियाँ लगभग समान हैं; केवल नाम अलग है। एक तीसरे समूह का अर्थ है तीसरी पंक्ति, चौथे का मतलब चौथी।

समस्या टाइपिंग की नहीं है — कॉपी करना आसान है। समस्या यह है कि एक ही निर्णय अब कई स्थानों पर लिखा गया है। यदि औसत को दो दशमलव स्थानों के बजाय एक स्थान तक दिखाने के लिए कहा जाए, तो आपको हर पंक्ति को खोजना और बदलना होगा, और एक को भी छोड़ देने से प्रोग्राम दो अलग-अलग तरीकों से व्यवहार करने लगेगा — बिना किसी त्रुटि के।

और एक खाली सूची के बारे में क्या? sum([]) / len([]) शून्य से विभाजित करता है और प्रोग्राम रुक जाता है। वह जाँच प्रत्येक पंक्ति में अलग से जोड़नी होगी।

एक फ़ंक्शन (Function) एक निर्णय को एक बार लिखने और उसे एक नाम देने का एक तरीका है। उसके बाद, केवल नाम को कॉल करने से काम हो जाता है, और इसे बदलने का अर्थ केवल एक जगह बदलना है।

इस मिशन के अंत तक आप सीखेंगे

  • def के साथ एक फ़ंक्शन लिखना और कॉल करना
  • return और print के बीच अंतर बताना — इस अध्याय का सबसे महत्वपूर्ण बिंदु
  • एक फ़ंक्शन को छोटा और केवल एक काम तक सीमित रखना
  • सबसे ऊपर एक गार्ड (guard) के साथ किनारे के मामलों (edge cases) को संभालना
  • डॉकस्ट्रिंग (docstring) लिखना

पूर्वापेक्षाएँ: कॉम्प्रिहेंशन — एक पंक्ति में लूप.


पहला फ़ंक्शन

python
def average(values):
    return round(sum(values) / len(values), 2)


print(average([72, 45]))
print(average([90, 33, 61]))
text
58.5
61.33

संरचना:

  • def — "मैं एक फ़ंक्शन परिभाषित कर रहा हूँ"
  • average — नाम, जो चर नाम के समान नियमों का पालन करता है
  • (values) — पैरामीटर (parameter), वह दरवाज़ा जिससे डेटा अंदर आता है
  • : और एक इंडेंटेड ब्लॉक — बॉडी
  • return — परिणाम वापस भेजना

average([72, 45]) लिखना इसे कॉल करना (calling) है। [72, 45] तर्क (argument) है, जो वास्तव में भेजा गया है; values पैरामीटर है, अंदर का नाम।

दो खाली पंक्तियाँ: फ़ंक्शन परिभाषा के बाद दो खाली पंक्तियाँ छोड़ना पायथन की परंपरा (PEP 8) है।

return और print एक समान नहीं हैं

यह इस अध्याय का सबसे महत्वपूर्ण खंड है, और शुरुआती लोगों का सबसे बड़ा भ्रम है।

python
def with_return(x):
    return x * 2


def with_print(x):
    print(x * 2)


a = with_return(5)
b = with_print(5)

print(a)
print(b)
print(a + 1)
text
10
10
None
11

स्क्रीन पर पहले दो 10 फ़ंक्शंस को एक जैसा दिखाते हैं। वे नहीं हैं।

with_return ने मान वापस लौटाया, इसलिए a में 10 संग्रहीत है और इसमें जोड़ा जा सकता है — इसलिए अंतिम पंक्ति पर 11।

with_print ने मान प्रदर्शित किया और कुछ भी वापस नहीं लौटाया, इसलिए b का मान None है। संख्या स्क्रीन पर दिखाई दी, और प्रोग्राम को कुछ नहीं मिला। b + 1 लिखने पर TypeError आएगा।

नियम को इस तरह याद रखें: print व्यक्ति के लिए है, return प्रोग्राम के लिए है। गणना करने वाले फ़ंक्शन को return करना चाहिए; प्रदर्शन वहाँ होता है जहाँ इसे कॉल किया गया था।

return के बिना, फ़ंक्शन चुपचाप None लौटाता है।

return तुरंत रुक जाता है

python
def check(mark):
    if mark >= 40:
        return "pass"
    return "fail"


print(check(72))
print(check(20))
text
pass
fail

जिस क्षण return चलता है, फ़ंक्शन समाप्त हो जाता है — इसके बाद की पंक्तियाँ कभी नहीं चलती हैं। इसीलिए यहाँ किसी else की आवश्यकता नहीं थी।

किनारों को संभालना — एक गार्ड (Guard)

अध्याय की शुरुआत में खाली सूची वाली समस्या याद है?

python
def average(values):
    return sum(values) / len(values)


print(average([]))
text
ZeroDivisionError: division by zero

इसका समाधान फ़ंक्शन के शीर्ष पर जाता है:

python
def average(values):
    if not values:
        return 0.0
    return round(sum(values) / len(values), 2)


print(average([72, 45]))
print(average([]))
text
58.5
0.0

if not values ट्रुथीनेस का नियम है: एक खाली सूची falsy होती है, इसलिए not इसे true बना देता है।

इसे गार्ड (guard) कहा जाता है: असामान्य स्थिति से शीर्ष पर निपटें, फिर बाकी कोड बिना किसी चिंता के लिखें।

डॉकस्ट्रिंग्स (Docstrings)

फ़ंक्शन की पहली पंक्ति पर टेक्स्ट का एक टुकड़ा उसका दस्तावेज़ीकरण बन जाता है:

python
def average(values):
    """Return the mean of values, or 0.0 when there are none."""
    if not values:
        return 0.0
    return round(sum(values) / len(values), 2)


print(average([1, 2, 3]))
print(average.__doc__)
text
2.0
Return the mean of values, or 0.0 when there are none.

यह सामान्य टिप्पणी से अलग है क्योंकि यह चलते हुए प्रोग्राम में जीवित रहता है — संपादक इसे दिखाते हैं, और help(average) इसे प्रिंट करता है।


एक संपूर्ण उदाहरण

report.py:

python
# तीन छोटे फ़ंक्शन, प्रत्येक एक काम कर रहा है
def average(values):
    """Return the mean of values, or 0.0 when there are none."""
    if not values:
        return 0.0
    return round(sum(values) / len(values), 2)


def grade(mark):
    """Turn a mark into a letter."""
    if mark >= 80:
        return "A"
    if mark >= 70:
        return "B"
    if mark >= 40:
        return "C"
    return "F"


def summarise(name, marks):
    """Build one report line for a person."""
    mean = average(marks)
    return f"{name:<8} {len(marks):>2} papers  avg {mean:>6}  grade {grade(mean)}"


people = {
    "rafi": [72, 88, 61],
    "ahmed": [45, 38],
    "dia": [],
}

for name, marks in people.items():
    print(summarise(name, marks))
text
rafi      3 papers  avg  73.67  grade B
ahmed     2 papers  avg   41.5  grade C
dia       0 papers  avg    0.0  grade F

चार बातें ध्यान देने योग्य हैं:

प्रत्येक फ़ंक्शन एक काम करता है। average औसत निकालता है, grade एक ग्रेड अक्षर देता है, summarise एक पंक्ति बनाता है। उनमें से कोई भी प्रिंट नहीं करता — प्रिंटिंग नीचे लूप में एक ही स्थान पर होती है।

फ़ंक्शंस अन्य फ़ंक्शंस को कॉल करते हैं। summarise कॉल करता है average और grade को।

grade में कोई else नहीं है। प्रत्येक return फ़ंक्शन को रोक देता है।

dia की खाली सूची ने कुछ नहीं तोड़ा। गार्ड ने 0.0 लौटाया, grade ने इसे F में बदल दिया, और रिपोर्ट लाइन सामान्य रूप से प्रिंट हुई।


जब यह टूटता है

NameError: name 'greet' is not defined — लेकिन फ़ंक्शन वहीं है इसे इसकी def पंक्ति चलने से पहले कॉल किया गया था। पायथन फ़ाइल को ऊपर से नीचे पढ़ता है, और नाम तब तक मौजूद नहीं होता जब तक def निष्पादित नहीं होता। सभी def ऊपर रखें और कॉल करने वाला कोड नीचे।

TypeError: average() missing 1 required positional argument: 'values' कोई तर्क (argument) नहीं दिया गया था — average(marks) के बजाय average()।

फ़ंक्शन None लौटाता है कोई return नहीं है, या गलत इंडेंटेशन पर है। एक अन्य सामान्य कारण: जहाँ return लिखना था वहाँ print लिखा गया था।

फ़ंक्शन के अंदर का वेरिएबल बाहर दिखाई नहीं देता यह अपेक्षित है — इसका कारण अध्याय 21 का विषय है। अभी के लिए: बाहर जो कुछ भी चाहिए उसे return करें।