Skip to content
This page has been auto-translated and may contain errors.View in English

फ़ंक्शन्स

docs.scrimba.com

जैसे-जैसे आपके प्रोग्राम्स बड़े होते हैं, आप एक ही लॉजिक को एक से अधिक जगह लिखेंगे। फ़ंक्शन्स आपको लॉजिक को एक बार लिखने, उसे नाम देने, और हर जगह उपयोग करने देते हैं। इसे एक जगह ठीक करें और हर कॉल को ठीक किया जाता है।

फ़ंक्शन्स कोड पुनः उपयोग और एब्सट्रैक्शन की मुख्य इकाई हैं। वे एक व्यवहार को लपेटते हैं, उसे एक नाम देते हैं, एक स्पष्ट इंटरफेस को परिभाषित करते हैं (इसके पैरामीटर्स और रिटर्न वैल्यू), और इसे कहीं से भी कॉल करने योग्य बनाते हैं। अच्छी तरह से नाम दिए गए फ़ंक्शन्स भी डॉक्यूमेंटेशन के रूप में पढ़े जाते हैं: validate_email() आपको बॉडी को पढ़े बिना बताता है कि कोड का एक ब्लॉक क्या करता है।

Python में एक फ़ंक्शन एक first-class ऑब्जेक्ट है: एक वैल्यू जिसे आप किसी और की तरह पास कर सकते हैं, इसलिए इसे एक वेरिएबल को असाइन किया जा सकता है, एक लिस्ट या डिक्ट में स्टोर किया जा सकता है, दूसरे फ़ंक्शन को एक आर्गुमेंट के रूप में दिया जा सकता है, और एक से रिटर्न किया जा सकता है। def उस ऑब्जेक्ट को बनाता है और इसे वर्तमान स्कोप में एक नाम से बाँधता है (कोड का क्षेत्र जहाँ वह नाम दिखाई देता है)। फ़ंक्शन्स को वैल्यूज़ के रूप में व्यवहार करना ही है जो sorted(key=...) जैसे पैटर्न्स और छोटे प्लगइन टेबल्स को संभव बनाता है, और यह जल्दी आरामदायक होने लायक है।

python
def greet(name):
    return f"Hello, {name}!"

print(greet("अरुण"))   # "Hello, अरुण!"
print(greet("भारत"))     # "Hello, भारत!"

इसे एक बार लिखें, हर जगह उपयोग करें, एक जगह ठीक करें।

एक फ़ंक्शन को परिभाषित करना

def कीवर्ड एक फ़ंक्शन परिभाषा शुरू करता है, उसके बाद नाम, कोष्ठक, एक कोलन, और एक इंडेंटेड बॉडी आती है। एक फ़ंक्शन तब तक कुछ नहीं करता जब तक आप इसे कॉल नहीं करते। इसे def से परिभाषित करें, फिर इसे () के साथ नाम से कॉल करें।

def एक फ़ंक्शन ऑब्जेक्ट बनाता है और इसे वर्तमान स्कोप में दिए गए नाम से बाँधता है। बॉडी को परिभाषा के समय निष्पादित नहीं किया जाता है; यह केवल तब चलता है जब फ़ंक्शन को कॉल किया जाता है। return स्टेटमेंट के बिना फ़ंक्शन्स निहित रूप से None रिटर्न करते हैं।

def एक फ़ंक्शन ऑब्जेक्ट बनाता है और इसे वर्तमान स्कोप में नाम से बाँधता है। बॉडी को तब नहीं चलाया जाता है जब Python def को पढ़ता है, यह केवल तब चलता है जब आप फ़ंक्शन को कॉल करते हैं। यह विभाजन व्यावहारिक रूप से मायने रखता है: फ़ंक्शन बॉडी के अंदर एक टाइपो (एक नाम जो मौजूद नहीं है, कहें) चुप रहता है जब तक फ़ंक्शन को वास्तव में कॉल न किया जाए, इसलिए एक फ़ंक्शन जिसे आप कभी कॉल नहीं करते, एक NameError को छुपा सकता है जो केवल प्रोडक्शन में सामने आता है जिस दिन कोई इसे कॉल करता है।

python
def say_hello():
    print("Hello!")

say_hello()   # फ़ंक्शन को कॉल करें
Junoएक फ़ंक्शन को परिभाषित करनाdef name(): लिखें और बॉडी को नीचे इंडेंट करें। जब तक आप इसे name() के साथ कॉल नहीं करते कुछ नहीं होता, def केवल इसे सेट अप करता है। और अगर आप एक return भूल जाते हैं, तो फ़ंक्शन शांति से None वापस करता है, जो शुरुआत में मुझे एक से अधिक बार पकड़ा गया।
Junoएक फ़ंक्शन को परिभाषित करनाdef फ़ंक्शन बनाता है और इसे एक नाम से बाँधता है, लेकिन बॉडी केवल तब चलता है जब आप इसे कॉल करते हैं। कोई return नहीं मतलब फ़ंक्शन None रिटर्न करता है। इसे याद रखें जब कोई परिणाम किसी कारण के बिना खाली आता है।
Junoएक फ़ंक्शन को परिभाषित करना बॉडी `def` के समय नहीं चलता है, केवल तब जब आप फ़ंक्शन को कॉल करते हैं, इसलिए अंदर एक टूटा हुआ नाम तब तक अनजान रह सकता है जब तक कोई इसे वास्तव में कॉल न करे। कोई `return` के बिना एक फ़ंक्शन `None` रिटर्न करता है, जो एक अपना शांत बग है जब एक कॉलर एक वैल्यू की उम्मीद करता है।

पैरामीटर्स और आर्गुमेंट्स

पैरामीटर्स आपके फ़ंक्शन की अपेक्षित इनपुट्स हैं। उन्हें कोष्ठक के अंदर सूचीबद्ध करें। जब आप फ़ंक्शन को कॉल करते हैं, तो आप जो वैल्यूज़ पास करते हैं उन्हें पैरामीटर्स के साथ क्रम में मैच किया जाता है।

पैरामीटर्स एक फ़ंक्शन के इंटरफेस को परिभाषित करते हैं। आर्गुमेंट्स कॉल के समय पास की गई ठोस वैल्यूज़ हैं। पोजिशनल आर्गुमेंट्स पोजिशन से मैच किए जाते हैं; कीवर्ड आर्गुमेंट्स नाम से मैच किए जाते हैं। डिफ़ॉल्ट वैल्यूज़ पैरामीटर्स को ऑप्शनल बनाती हैं।

कॉल के समय, पोजिशनल आर्गुमेंट्स बाएं से दाएं बाँधते हैं और कीवर्ड आर्गुमेंट्स नाम से बाँधते हैं। एक ही पैरामीटर को दोनों तरीकों से पास करना, या एक जिसे Python न सकता हो, कॉल पर TypeError बढ़ाता है, बॉडी के अंदर नहीं। Python आपको एक हस्ताक्षर को भी सीमित करने देता है: एक नंगा * इसके बाद सबकुछ को कीवर्ड-ऑनली बनाता है (कॉलर्स को इसे नाम देना होगा), और एक / इसके पहले सबकुछ को पोजिशनल-ऑनली बनाता है। बूलियन फ़्लैग्स पर कीवर्ड-ऑनली तक पहुँचें और चौड़े हस्ताक्षर, जहाँ एक गलत जगह पर पोजिशनल True उस तरह की गलती है जो ठीक से कंपाइल होती है और एक बग शिप करती है।

python
def greet(name, greeting):
    print(f"{greeting}, {name}!")

greet("अरुण", "नमस्ते")    # "नमस्ते, अरुण!"
greet("भारत", "हाय")         # "हाय, भारत!"

पैरामीटर फ़ंक्शन परिभाषा में नाम है। आर्गुमेंट वास्तविक वैल्यू है जिसे आप कॉल करते समय देते हैं। व्यावहारिक रूप से लोग शब्दों का परस्पर उपयोग करते हैं; भेद मुख्य रूप से तब मायने रखता है जब डॉक्स पढ़ते हैं।

Junoपैरामीटर्स और आर्गुमेंट्स पैरामीटर्स वे नाम हैं जिन्हें आप कोष्ठक में सूचीबद्ध करते हैं, आर्गुमेंट्स वास्तविक वैल्यूज़ हैं जिन्हें आप कॉल करते समय देते हैं। Python उन्हें बाएं से दाएं पंक्तिबद्ध करता है, इसलिए जिस क्रम में आप उन्हें पास करते हैं वह क्रम है जिसमें वे आते हैं।
Junoपैरामीटर्स और आर्गुमेंट्स पैरामीटर्स परिभाषा में नाम हैं, आर्गुमेंट्स कॉल पर वैल्यूज़ हैं। पोजिशनल वाले बाएं से दाएं बाँधते हैं, इसलिए पोजिशन अनुबंध है। दोनों शब्दों का परस्पर उपयोग किया जाता है, अंतर मुख्य रूप से तब मायने रखता है जब आप डॉक्स पढ़ते हैं।
Junoपैरामीटर्स और आर्गुमेंट्स पोजिशनल आर्गुमेंट्स बाएं से दाएं बाँधते हैं, कीवर्ड वाले नाम से, और एक टकराव कॉल पर तुरंत `TypeError` बढ़ाता है। एक नंगा `*` कॉलर्स को इसके बाद जो आता है उसे नाम देने के लिए मजबूर करता है, जो एक फ़ंक्शन के `True`/`False` फ़्लैग्स के लिए सस्ता ठीक है जो अन्यथा कॉल साइट पर एक अनुमान का खेल होता।

डिफ़ॉल्ट वैल्यूज़

आप पैरामीटर्स को एक डिफ़ॉल्ट वैल्यू दे सकते हैं। अगर कॉलर वह आर्गुमेंट नहीं देता है, तो डिफ़ॉल्ट का उपयोग किया जाता है। डिफ़ॉल्ट वैल्यूज़ वाले पैरामीटर्स को डिफ़ॉल्ट वैल्यूज़ के बिना पैरामीटर्स के बाद आना चाहिए।

डिफ़ॉल्ट वैल्यूज़ पैरामीटर्स को ऑप्शनल बनाती हैं। वे परिभाषा के समय एक बार मूल्यांकन किए जाते हैं, प्रत्येक कॉल पर नहीं। यह म्यूटेबल डिफ़ॉल्ट्स के लिए मायने रखता है: def f(items=[]) सभी कॉल्स में एक ही लिस्ट साझा करता है। ठीक करना है None को डिफ़ॉल्ट के रूप में उपयोग करना और फ़ंक्शन बॉडी के अंदर लिस्ट बनाना।

विवरण जो काटता है: एक डिफ़ॉल्ट वैल्यू एक बार बनाई जाती है, जब def चलता है, और हर कॉल द्वारा साझा किया जाता है जो इसे उपयोग करता है। एक अपरिवर्तनीय डिफ़ॉल्ट के लिए जैसे 0 या "Hello" (एक जिसे आप स्थान पर नहीं बदल सकते) वह ठीक है। एक म्यूटेबल डिफ़ॉल्ट के लिए जैसे एक लिस्ट या डिक्ट (एक जिसे आप स्थान पर बदल सकते हैं) यह एक जाल है, क्योंकि हर कॉल जो डिफ़ॉल्ट पर वापस गिरता है एक ही ऑब्जेक्ट का पुनः उपयोग करता है:

python
def add_item(item, items=[]):   # लिस्ट को एक बार बनाया जाता है, हमेशा के लिए साझा किया जाता है
    items.append(item)
    return items

add_item("a")   # ['a']
add_item("b")   # ['a', 'b']  <- एक ताजी लिस्ट नहीं

ठीक करना है मानक: None को डिफ़ॉल्ट करें, फिर बॉडी के अंदर एक ताजा कंटेनर बनाएं।

python
def add_item(item, items=None):
    if items is None:
        items = []
    items.append(item)
    return items
python
def greet(name, greeting="नमस्ते"):
    print(f"{greeting}, {name}!")

greet("अरुण")           # "नमस्ते, अरुण!"
greet("अरुण", "हाय")     # "हाय, अरुण!"

डिफ़ॉल्ट वैल्यूज़ वाले पैरामीटर्स को डिफ़ॉल्ट वैल्यूज़ के बिना पैरामीटर्स के बाद आना चाहिए।

Junoडिफ़ॉल्ट वैल्यूज़ एक पैरामीटर को डिफ़ॉल्ट दें और यह ऑप्शनल बन जाता है, कॉलर इसे छोड़ सकता है। डिफ़ॉल्ट वाले को आवश्यक वाले के बाद आना पड़ता है, यह क्रम एक नियम है जो Python लागू करता है। आपको हर कॉल पर एक ही वैल्यू लिखना बचाता है।
Junoडिफ़ॉल्ट वैल्यूज़ डिफ़ॉल्ट्स एक पैरामीटर को ऑप्शनल बनाती हैं और आवश्यक वाले के बाद बैठनी चाहिए। पकड़: एक डिफ़ॉल्ट परिभाषा पर मूल्यांकन किया जाता है, इसलिए कभी एक म्यूटेबल न जैसे [] का उपयोग न करें। बॉडी के अंदर इसके बजाय None को डिफ़ॉल्ट करें और लिस्ट बनाएं।
Junoडिफ़ॉल्ट वैल्यूज़ एक डिफ़ॉल्ट def के समय बनाई जाती है और कॉल्स में साझा की जाती है, इसलिए items=[] शांति से कॉल्स के बीच जमा होता है। None को डिफ़ॉल्ट करें और बॉडी में एक ताजा बनाएं। यह लगभग किसी भी अन्य Python स्लिप से अधिक वास्तविक कोड समीक्षा में दिखाई देता है।

कीवर्ड आर्गुमेंट्स

फ़ंक्शन को कॉल करते समय, आप आर्गुमेंट्स को नाम दे सकते हैं। यह कॉल्स को पठनीय बनाता है, विशेष रूप से कई पैरामीटर्स वाले फ़ंक्शन्स के लिए, और आपको उन्हें किसी भी क्रम में पास करने देता है।

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

कीवर्ड आर्गुमेंट्स नाम से बाँधते हैं, इसलिए वे अच्छी तरह पढ़ते हैं और आपको पोजिशन्स को याद रखने से मुक्त करते हैं। कॉल साइट पर नियम: पोजिशनल आर्गुमेंट्स पहले आते हैं, कीवर्ड वाले बाद में, और एक ही पैरामीटर को दोनों तरीकों से नाम देना TypeError बढ़ाता है। डिज़ाइन का कदम जो करने लायक है वह रिवर्स है: एक नंगा * अपने हस्ताक्षर में डालें ताकि कॉलर्स एक पैरामीटर को नाम दें (def connect(host, *, timeout=30))। इसकी कोई कीमत नहीं है और एक अस्पष्ट connect("db", 30) को एक connect("db", timeout=30) में बदल देता है जो किसी के बाद एक पैरामीटर जोड़ने पर जीवित रहता है।

python
def describe_player(name, score, level):
    print(f"{name} | Score: {score} | Level: {level}")

describe_player("अरुण", 87, 5)                        # पोजिशनल
describe_player(name="अरुण", level=5, score=87)       # कीवर्ड, कोई भी क्रम
describe_player("अरुण", level=5, score=87)            # मिश्रण: पोजिशनल पहले
Junoकीवर्ड आर्गुमेंट्स कॉल पर आर्गुमेंट्स को नाम दें (score=87) और कॉल अपने आप को समझाता है, साथ ही आप उन्हें किसी भी क्रम में पास कर सकते हैं। एक नियम: कोई पोजिशनल आर्गुमेंट्स नाम वाले से पहले आना चाहिए। बहुत सारे पैरामीटर्स वाले फ़ंक्शन्स के लिए बहुत अच्छा।
Junoकीवर्ड आर्गुमेंट्स आर्गुमेंट्स को नाम देना एक कॉल को आत्म-दस्तावेज़ बनाता है और क्रम-स्वतंत्र, पोजिशनल वाले को पहले आना आवश्यक है। चौड़े हस्ताक्षर्स या बूलियन फ़्लैग्स के लिए, कीवर्ड आर्गुमेंट्स को प्राथमिकता दें ताकि कोई भी कॉल को पढ़ने के लिए पोजिशन्स न गिनना पड़े।
Junoकीवर्ड आर्गुमेंट्स कीवर्ड आर्गुमेंट्स नाम से बाँधते हैं और किसी पोजिशनल वाले के बाद आने चाहिए। वास्तविक लीवर आपका अपना हस्ताक्षर है: एक नंगा * कॉलर्स को इसके बाद जो आता है उसे नाम देने के लिए मजबूर करता है, इसलिए कॉल सही तरीके से पढ़ता है जब कोई बीच में एक नया पैरामीटर स्लॉट करता है।

रिटर्न वैल्यूज़

return कॉलर को एक वैल्यू भेजता है। बिना return के, एक फ़ंक्शन None देता है। एक बार return चलता है, फ़ंक्शन तुरंत बाहर निकलता है। उस ब्लॉक में इसके बाद का कोई भी कोड छोड़ दिया जाता है।

return फ़ंक्शन को बाहर निकालता है और कॉलर को एक वैल्यू पास करता है। स्पष्ट return के बिना एक फ़ंक्शन निहित रूप से None रिटर्न करता है। return फ़ंक्शन बॉडी में कहीं भी दिखाई दे सकता है और कई बार उपयोग किया जा सकता है; पहला वह जो पहुँचता है फ़ंक्शन को समाप्त करता है। यह गार्ड क्लॉज़ के लिए शुरुआती रिटर्न्स को उपयोगी बनाता है।

return एक वैल्यू कॉलर को देता है और फ़ंक्शन को तुरंत समाप्त करता है, और एक फ़ंक्शन जो बिना return के अंत में चलता है None रिटर्न करता है। एकाधिक रिटर्न्स अच्छी शैली हैं, गंध नहीं: विफलता या किनारे के मामले के लिए ऊपर एक प्रारंभिक return (गार्ड क्लॉज़ पैटर्न) पूरी बॉडी को एक बड़े if के अंदर नेस्ट करने से बहुत बेहतर पढ़ता है। सूक्ष्मता को जानना पहले आश्चर्यजनक है: एक try ब्लॉक के अंदर एक return अभी भी पहले मिलान finally ब्लॉक को चलाता है, इसलिए finally में सफाई एक प्रारंभिक रिटर्न पर भी होती है।

python
def add(a, b):
    return a + b

result = add(3, 4)   # result = 7
print(result)

return भी तुरंत फ़ंक्शन को बाहर निकालता है। उस ब्लॉक में इसके बाद का कोई भी कोड नहीं चलता है।

Junoरिटर्न वैल्यूज़return फ़ंक्शन को कॉल करने वाले को एक वैल्यू देता है, और फ़ंक्शन वहीं बंद हो जाता है, इसके बाद कुछ भी छोड़ दिया जाता है। `return` को छोड़ दें और आप None वापस पाते हैं। print एक वैल्यू दिखाता है, return इसे उपयोग करने के लिए देता है, मुझे वह अंतर महसूस करने में एक समय लगा।
Junoरिटर्न वैल्यूज़return एक वैल्यू पास करता है और तुरंत बाहर निकलता है, कोई return का मतलब `None` है। आप कई हो सकते हैं, और किनारे के मामले के लिए ऊपर एक प्रारंभिक return आमतौर पर सबकुछ को एक बड़े if में लपेटने से अधिक स्वच्छ पढ़ता है।
Junoरिटर्न वैल्यूज़return तुरंत बाहर निकलता है और अंत में गिरना `None` देता है। गहरी नेस्टिंग के बजाय गार्ड क्लॉज़ के रूप में प्रारंभिक रिटर्न्स पर झुकें। और याद रखें एक try के अंदर एक return अभी भी finally ब्लॉक को चलाता है, इसलिए वहाँ सफाई एक प्रारंभिक निकास पर भी होती है।

एकाधिक वैल्यूज़ रिटर्न करना

Python आपको कॉमा के साथ एकाधिक वैल्यूज़ को अलग करके रिटर्न करने देता है। कॉलर उन्हें एक ट्यूपल के रूप में प्राप्त करता है और उन्हें एक लाइन में अलग नामों में अनपैक कर सकता है।

कॉमा के साथ एकाधिक वैल्यूज़ रिटर्न करना उन्हें एक ट्यूपल में पैक करता है। कॉलर मिलान नामों के साथ अनपैक करता है। यह उन फ़ंक्शन्स के लिए Python की मुहावरेदार है जो स्वाभाविक रूप से एक से अधिक परिणाम देते हैं। यह एक विशेष फीचर नहीं है; यह ट्यूपल पैकिंग और अनपैकिंग है।

return a, b वैल्यूज़ को एक ट्यूपल में पैक करता है, और कॉलर उन्हें low, high = f() के साथ अलग करता है। यह दो या तीन परिणामों के लिए स्वच्छ रूप से पढ़ता है। उसके आगे, पोजिशन एक देयता बन जाता है: फ़ंक्शन को कॉल करने वाला कोई भी याद नहीं रखता है कि तीसरी वस्तु गणना थी या औसत, और एक स्वैप्ड जोड़ी एक शांत बग है। उस समय कुछ नाम वाली चीज़ रिटर्न करें, एक NamedTuple या एक @dataclass, ताकि कॉलर्स result[2] के बजाय result.average के लिए पहुँचें। रिटर्न को tuple[int, str] के रूप में किसी भी तरीके से एनोटेट करें ताकि एक टाइप चेकर एक कॉलर को गलत संख्या में वैल्यूज़ अनपैक करने को पकड़ सके।

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

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

low, high = ... सिंटैक्स अनपैकिंग है: Python रिटर्न की गई हर वैल्यू को संगत नाम को असाइन करता है।

Junoएकाधिक वैल्यूज़ रिटर्न करना वैल्यूज़ को कॉमा के साथ अलग करें और फ़ंक्शन उन्हें एक ट्यूपल के रूप में एक साथ रिटर्न करता है। कॉलर एक लाइन में उन्हें पकड़ता है, low, high = min_max(...), एक नाम प्रति वैल्यू। सुविधाजनक जब भी एक फ़ंक्शन स्वाभाविक रूप से एक से अधिक उत्तर देता है।
Junoएकाधिक वैल्यूज़ रिटर्न करना एक कॉमा एक ट्यूपल में वैल्यूज़ को पैक करता है, कॉलर मिलान नामों के साथ अनपैक करता है। यह सादा ट्यूपल पैकिंग और अनपैकिंग है, कोई विशेष फीचर नहीं। दो या तीन परिणामों के लिए स्वच्छ, उसके आगे कम।
Junoएकाधिक वैल्यूज़ रिटर्न करना कॉमा-रिटर्न एक ट्यूपल पैक करता है, दो या तीन वैल्यूज़ के लिए ठीक। उसके आगे, पोजिशन एक जाल बन जाता है कोई भी पढ़ नहीं सकता, इसलिए एक `NamedTuple` या `@dataclass` रिटर्न करें और कॉलर्स को इंडेक्स गिनने के बजाय `result.average` का उपयोग करने दें।

स्कोप

फ़ंक्शन के अंदर बनाए गए वेरिएबल्स केवल उस फ़ंक्शन के अंदर मौजूद होते हैं। आप उन्हें बाहर से नहीं देख सकते। सभी फ़ंक्शन्स के बाहर परिभाषित वेरिएबल्स हर जगह दिखाई देते हैं, लेकिन आप एक स्पष्ट घोषणा के बिना फ़ंक्शन के अंदर से उन्हें बदल नहीं सकते।

फ़ंक्शन के अंदर बनाया गया एक नाम स्थानीय है: यह केवल वहीं रहता है और फ़ंक्शन रिटर्न करने पर गायब हो जाता है। फ़ाइल के शीर्ष स्तर पर परिभाषित एक नाम वैश्विक है। फ़ंक्शन के अंदर से एक वैश्विक को पढ़ना बिना समारोह के काम करता है, लेकिन एक को असाइन करने के लिए global name की आवश्यकता है, अन्यथा Python असाइनमेंट को एक नई स्थानीय बनाने के रूप में मानता है जो वैश्विक को छायांकित करता है। व्यावहारिक रूप से आप global को बिलकुल नहीं चाहते: तर्कों में वैल्यूज़ पास करना और परिणामों को return के साथ वापस करना एक फ़ंक्शन के प्रभाव को कॉल साइट पर दृश्यमान रखता है।

Python एक नाम को LEGB नियम के साथ हल करता है, चार जगहों को क्रम में जाँचता है: Local (यह फ़ंक्शन), Enclosing (एक बाहरी फ़ंक्शन जो इसे लपेटता है), Global (मॉड्यूल), फिर Built-in (नाम जैसे len)। पढ़ना वह श्रृंखला चलता है; असाइनमेंट हमेशा एक स्थानीय बनाता है जब तक आप अन्यथा न कहें। यह असमरूपता बग स्रोत है: बिना global count लाइन के एक वैश्विक के विरुद्ध count += 1 UnboundLocalError बढ़ाता है, क्योंकि असाइनमेंट पूरे फ़ंक्शन के लिए count को स्थानीय चिह्नित करता है और पढ़ना किसी भी स्थानीय वैल्यू के मौजूद होने से पहले होता है। global name असाइनमेंट को मॉड्यूल स्तर पर वापस करता है; nonlocal name निकटतम संलग्न फ़ंक्शन के बजाय लक्ष्य करता है, जो यह है कि एक क्लोज़र इसे बनाने वाले फ़ंक्शन से एक वेरिएबल कैसे अपडेट करता है। दोनों को एक गंध के रूप में मानें: एक फ़ंक्शन जो बाहरी अवस्था को उत्परिवर्तित करने के लिए पहुँचता है एक ऐसे से परीक्षण करना कठिन है जो इनपुट्स लेता है और आउटपुट्स रिटर्न करता है।

Junoस्कोप एक फ़ंक्शन के अंदर बनाया गया एक वेरिएबल केवल वहीं रहता है, बाहर इसे नहीं देख सकता। आप अंदर से एक बाहरी वेरिएबल को पढ़ सकते हैं, लेकिन एक को बदलने के लिए पहले एक global लाइन की आवश्यकता है। लगभग कभी भी इसे न करें: वैल्यूज़ को अंदर पास करें, परिणामों को बाहर रिटर्न करें, और फ़ंक्शन सरल रहता है।
Junoस्कोप फ़ंक्शन के अंदर बनाए गए नाम स्थानीय हैं और यह रिटर्न करने पर चले जाते हैं। एक वैश्विक को पढ़ना मुक्त है, एक को लिखने के लिए global name की आवश्यकता है या Python एक स्थानीय बनाता है जो इसे छायांकित करता है। तर्कों में और `return` में बाहर करने के लिए वरीयता दें ताकि एक फ़ंक्शन के प्रभाव कॉल पर दृश्यमान रहें।
Junoस्कोप लुकअप के लिए LEGB, लेकिन असाइनमेंट हमेशा एक स्थानीय बनाता है जब तक आप global या nonlocal घोषित न करें, जिसका कारण `count += 1` एक वैश्विक पर `UnboundLocalError` फेंकता है। दोनों कीवर्ड्स एक गंध हैं: एक फ़ंक्शन जो बाहरी अवस्था को उत्परिवर्तित करता है परीक्षण करना मुश्किल है एक ऐसे से जो इनपुट लेता है और आउटपुट्स रिटर्न करता है।
python
def calculate():
    result = 42   # इस फ़ंक्शन के लिए स्थानीय
    return result

calculate()
print(result)   # NameError, result यहाँ मौजूद नहीं है
python
count = 0

def increment():
    global count    # घोषित करें कि आप वैश्विक को संशोधित करना चाहते हैं
    count += 1

increment()
print(count)   # 1

global का उपयोग करना एक अंतिम उपाय होना चाहिए। यह कोड को समझने में कठिन बनाता है। वैल्यूज़ को अंदर पास करने और उन्हें बाहर रिटर्न करने के लिए वरीयता दें। स्कोप सीधे इस पर बनता है कि असाइनमेंट एक नाम को एक वैल्यू में कैसे बाँधता है, जिसे Variables and types अध्याय में शामिल किया गया है।

*args और **kwargs

कभी-कभी आप नहीं जानते कि एक फ़ंक्शन कितने आर्गुमेंट्स प्राप्त करेगा। *args किसी भी संख्या में पोजिशनल आर्गुमेंट्स को एक ट्यूपल में एकत्र करता है। **kwargs किसी भी संख्या में कीवर्ड आर्गुमेंट्स को एक डिक्शनरी में एकत्र करता है। args और kwargs के नाम सम्मेलन हैं; सितारे महत्वपूर्ण हैं।

*args अतिरिक्त पोजिशनल आर्गुमेंट्स को एक ट्यूपल में एकत्र करता है। **kwargs अतिरिक्त कीवर्ड आर्गुमेंट्स को एक डिक्ट में एकत्र करता है। दोनों को नियमित पैरामीटर्स के साथ जोड़ा जा सकता है। नियमित पैरामीटर्स पहले आते हैं, फिर *args, फिर कीवर्ड-ऑनली पैरामीटर्स, फिर **kwargs। वे आर्गुमेंट्स को दूसरे फ़ंक्शन के लिए पास करने वाले रैपर फ़ंक्शन्स के लिए उपयोगी हैं।

*args अतिरिक्त पोजिशनल आर्गुमेंट्स को एक tuple में एकत्र करता है, **kwargs अतिरिक्त कीवर्ड वाले को एक dict में एकत्र करता है। दर्पण छवि कॉल साइट पर होती है: func(*some_list) एक लिस्ट को पोजिशनल आर्गुमेंट्स में फैलाता है और func(**some_dict) एक डिक्ट को कीवर्ड वाले में फैलाता है। वह सममितता ही है जो एक पास-थ्रू रैपर को काम करने देती है, def timed(*args, **kwargs): return inner(*args, **kwargs) जो भी इसे एक ही पैरामीटर को नाम दिए बिना प्राप्त करता है। उपयोगी, लेकिन यह आपको पठनीय हस्ताक्षर की कीमत देता है: एक रैपर जो सबकुछ *args, **kwargs में निगल जाता है कॉलर्स और टाइप चेकर्स को दिखाता है कि यह क्या स्वीकार करता है, इसलिए जब आप वास्तव में मनमाने आर्गुमेंट्स को फॉरवर्ड करने की आवश्यकता है तब इसे पहुँचें, एक सामान्य फ़ंक्शन के लिए डिफ़ॉल्ट आकृति के रूप में नहीं।

python
def total(*args):
    return sum(args)

total(1, 2, 3)          # 6
total(1, 2, 3, 4, 5)   # 15
python
def display(**kwargs):
    for key, value in kwargs.items():
        print(f"{key}: {value}")

display(name="अरुण", score=87, level=5)

आप उन्हें नियमित पैरामीटर्स के साथ मिश्रित कर सकते हैं। नियमित पैरामीटर्स पहले आते हैं:

python
def describe(title, *tags, **metadata):
    print(f"{title} | tags: {tags} | meta: {metadata}")

describe("Python intro", "beginner", "python", author="अरुण", year=2024)
Juno*args और **kwargs*args किसी भी संख्या में अतिरिक्त पोजिशनल आर्गुमेंट्स को एक ट्यूपल के रूप में लेता है, **kwargs अतिरिक्त नाम दिए गए को एक डिक्ट के रूप में लेता है। शब्द args और kwargs केवल सम्मेलन हैं, * और ** वास्तविक काम करते हैं। सुविधाजनक जब आप आगे कह नहीं सकते कि कितनी चीज़ें आती हैं।
Juno*args और **kwargs*args अतिरिक्त पोजिशनल आर्गुमेंट्स को एक ट्यूपल में एकत्र करता है, **kwargs अतिरिक्त कीवर्ड वाले को एक डिक्ट में एकत्र करता है। हस्ताक्षर में क्रम: नियमित पैरामीटर्स, फिर `*args`, फिर कीवर्ड-ऑनली, फिर `**kwargs`। रैपर्स के लिए सबसे उपयोगी जो आर्गुमेंट्स को सीधे दूसरे फ़ंक्शन पर फॉरवर्ड करते हैं।
Juno*args और **kwargs हस्ताक्षर में `*` और `**` एकत्र करते हैं और कॉल साइट पर फैलाते हैं, जो एक रैपर को `inner(*args, **kwargs)` के साथ सबकुछ फॉरवर्ड करने देता है। कीमत एक हस्ताक्षर है जो कॉलर्स को कुछ नहीं बताता है, इसलिए इसे वास्तविक पास-थ्रू के लिए रखें, सामान्य फ़ंक्शन्स नहीं।

डॉकस्ट्रिंग्स

एक डॉकस्ट्रिंग एक फ़ंक्शन के शीर्ष पर एक स्ट्रिंग है जो वर्णन करता है कि यह क्या करता है। Python संपादक और टूल्स इसे दिखाने के लिए उपयोग करते हैं जब आप एक फ़ंक्शन कॉल पर होते हैं। ट्रिपल कोट्स का उपयोग करें, और सरल फ़ंक्शन्स के लिए एक लाइन लिखें।

एक डॉकस्ट्रिंग फ़ंक्शन बॉडी के शीर्ष पर है, ट्रिपल कोट्स में एक स्ट्रिंग। टूल्स इसे पढ़ते हैं: help(func) इसे प्रिंट करता है, और आपका संपादक इसे एक कॉल पर होवर करते हुए दिखाता है, इसलिए यह ठीक उसी समय भुगतान करता है जब आप भूल गए हों कि फ़ंक्शन क्या करता है। सम्मेलन एक सारांश लाइन है, फिर एक खाली लाइन और अधिक विस्तार यदि आवश्यक हो। इसे एक से अधिक जगह से कॉल किए जाने वाले कुछ पर आवश्यक के रूप में व्यवहार करें, एक फेंक देने वाले सहायक पर वैकल्पिक जिसका नाम पहले से ही सबकुछ कहता है।

एक डॉकस्ट्रिंग फ़ंक्शन, क्लास, या मॉड्यूल बॉडी में पहली स्टेटमेंट है, और यह कहना चाहिए कि फ़ंक्शन क्या करता है और यह क्या रिटर्न करता है, पैरामीटर सूची को फिर से नहीं कहना जिसे एक पाठक पहले से ही देख सकता है। यह उन सबपर कमाता है जिनके अनुबंध हस्ताक्षर से दृश्यमान नहीं हैं: किनारे के मामले, यह क्या बढ़ाता है, एक खाली इनपुट क्या करता है। औपचारिक arg-by-arg ब्लॉक छोड़ें जब टाइप हिंट्स हस्ताक्षर में पहले से ही प्रकार लेते हैं, वह विस्तार हिंट्स में, दोहराए गए गद्य में नहीं जो समय से बाहर निकलता है। लक्ष्य वह लाइन है जिसे आप सुबह 2 बजे एक कॉल को डीबग करते समय पढ़ना चाहेंगे जिसे आपने छह महीने पहले लिखा था।

python
def normalise(value, min_val, max_val):
    """दिए गए न्यूनतम और अधिकतम के अनुसार एक वैल्यू को 0-1 रेंज में स्केल करें।"""
    return (value - min_val) / (max_val - min_val)
python
def build_url(base, version, resource, *, secure=True):
    """
    एक API एंडपॉइंट URL बनाएं।

    एक पूरी तरह से योग्य URL स्ट्रिंग रिटर्न करता है। अगर secure False है,
    URL http के बजाय https का उपयोग करेगा।
    """
    scheme = "https" if secure else "http"
    base = base.replace("https://", "").replace("http://", "")
    return f"{scheme}://{base}/{version}/{resource}"

किसी भी फ़ंक्शन के लिए एक डॉकस्ट्रिंग लिखें जिसका उद्देश्य इसके नाम और हस्ताक्षर से स्पष्ट नहीं है।

Junoडॉकस्ट्रिंग्स एक डॉकस्ट्रिंग एक फ़ंक्शन के बिलकुल शीर्ष पर ट्रिपल कोट्स में एक स्ट्रिंग है, जो वर्णन करता है कि यह क्या करता है। आपका संपादक इसे दिखाता है जब आप फ़ंक्शन पर बाद में होते हैं, जिसके लिए आप खुश होंगे कि यह वहाँ है। एक बार लिखें जब भी नाम और इनपुट्स पहले से ही उद्देश्य को स्पष्ट न करें।
Junoडॉकस्ट्रिंग्स बॉडी की पहली लाइन, ट्रिपल-कोटेड: help() और आपका संपादक इसे होवर पर सामने लाते हैं। एक सारांश लाइन अधिकांश फ़ंक्शन्स को कवर करती है, केवल तब विवरण जोड़ें जब व्यवहार को इसकी आवश्यकता हो। कई जगह से कॉल किए जाने वाले किसी के पर आवश्यक, एक-पंक्ति पर छोड़ने योग्य जिसका नाम यह सबकुछ कहता है।
Junoडॉकस्ट्रिंग्स कहें कि फ़ंक्शन क्या करता है, यह क्या रिटर्न करता है, और किनारे के मामले, पैरामीटर सूची को नहीं दोहराया जिसे पाठक पहले से ही देख सकता है। टाइप हिंट्स को प्रकार लेने दें ताकि आप एक ही तथ्य दो बार न रखें। सुबह 2 बजे उस लाइन के लिए लक्ष्य रखें जिसे आप एक कॉल को डीबग करते हुए चाहेंगे जिसे आपने छह महीने पहले लिखा था।

टाइप हिंट्स

टाइप हिंट्स आपको यह एनोटेट करने देते हैं कि एक फ़ंक्शन क्या प्रकार की अपेक्षा करता है और क्या रिटर्न करता है। Python उन्हें रनटाइम पर लागू नहीं करता है, लेकिन संपादक उन्हें आप कुछ भी चलाने से पहले गलतियों को पकड़ने के लिए उपयोग करते हैं। कोलन से पहले -> रिटर्न प्रकार को निर्दिष्ट करता है।

टाइप हिंट्स डॉक्यूमेंटेशन हैं जो टूल्स सत्यापन करते हैं। संपादक और टाइप चेकर्स (mypy, pyright) उन्हें रनटाइम से पहले टाइप mismatches को पकड़ने के लिए उपयोग करते हैं। वे मानक Python में कोई रनटाइम प्रभाव नहीं रखते। -> None फ़ंक्शन्स के लिए सही एनोटेशन है जो रिटर्न नहीं करते। सामान्य कंटेनर्स के लिए, list[int], dict[str, int] का उपयोग करें (Python 3.9+)।

टाइप हिंट्स रनटाइम पर कुछ नहीं बदलते, Python उन्हें बिना या के साथ समान रूप से चलता है। उनका पूरा मूल्य प्रोग्राम के बाहर परत है: एक टाइप चेकर (mypy या pyright) कोड को चलाने से पहले पढ़ रहा है, और आपका संपादक एक बुरी कॉल को जैसे ही आप इसे टाइप करते हैं फ़्लैग कर रहा है। तो एक हिंट जो झूठ बोलता है कोई हिंट से बदतर है, क्योंकि चेकर इसे विश्वास करता है। list[int], dict[str, int] और str | None सीधे उपयोग करें (आधुनिक Python पर कोई typing आयात की आवश्यकता नहीं), और एक फ़ंक्शन को -> None के रूप में एनोटेट करें जो कुछ नहीं रिटर्न करता है, जो यह भी संकेत देता है कि इसे एक एक्सप्रेशन में कॉल करना (x = log(...)) एक गलती है। पेऑफ उन फ़ंक्शन्स पर भूमि जो कई जगह से कॉल किए जाते हैं: चेकर एक कॉलर को गलत प्रकार पास करने को पकड़ता है रनटाइम पर तीन फ्रेम गहरे एक भ्रामक विफलता के रूप में सामने आने के बजाय।

python
def greet(name: str, score: int) -> str:
    return f"{name} scored {score}"
python
def log(message: str) -> None:
    print(f"[LOG] {message}")
python
def top_scores(scores: list[int], n: int) -> list[int]:
    return sorted(scores, reverse=True)[:n]

टाइप हिंट्स ऑप्शनल हैं लेकिन कई जगह से कॉल किए जाने वाले किसी भी फ़ंक्शन पर मूल्यवान हैं। वे डॉक्यूमेंटेशन हैं जो टूल्स सत्यापन कर सकते हैं।

Junoटाइप हिंट्स टाइप हिंट्स नोट करते हैं कि एक फ़ंक्शन क्या लेता है और देता है, जैसे name: str और `-> str` रिटर्न के लिए। Python इसे चलाते समय लागू नहीं करेगा, लेकिन आपका संपादक इसे पढ़ता है और आपको चलाने से पहले चेतावनी देता है। उन्हें टूल्स के रूप में सोचें जो जाँच सकते हैं।
Junoटाइप हिंट्स हिंट्स डॉक्यूमेंटेशन हैं एक टाइप चेकर सत्यापन कर सकता है, कोई रनटाइम प्रभाव के साथ। `-> None` सही एनोटेशन है जब एक फ़ंक्शन कुछ नहीं रिटर्न करता है, और `list[int]` / `dict[str, int]` आधुनिक Python पर बिना `typing` आयात के काम करते हैं। कई जगह से कॉल किए जाने वाले किसी के पर इसके लायक।
Junoटाइप हिंट्स हिंट्स रनटाइम पर कुछ नहीं करते, उनका मूल्य चेकर और संपादक पढ़ रहा है, इसलिए एक हिंट जो झूठ है कोई नहीं से बदतर है। `str | None` और `list[int]` सीधे उपयोग करें, `-> None` कोई रिटर्न के लिए। जीत एक गलत-टाइप किए गए कॉलर को पकड़ना है इससे पहले कि वह तीन फ्रेम गहरा विफल हो।

फ़ंक्शन्स को वैल्यूज़ के रूप में

Python में फ़ंक्शन्स वैल्यूज़ हैं, स्ट्रिंग्स या संख्या की तरह। आप उन्हें वेरिएबल्स को असाइन कर सकते हैं और उन्हें दूसरे फ़ंक्शन्स को पास कर सकते हैं। यह है कि कैसे sorted() एक key= फ़ंक्शन को स्वीकार करता है।

फ़ंक्शन्स first-class ऑब्जेक्ट्स हैं: उनके पास एक प्रकार है (function), वेरिएबल्स और कलेक्शन्स में स्टोर किए जा सकते हैं, और आर्गुमेंट्स के रूप में पास किए जा सकते हैं या वैल्यूज़ के रूप में रिटर्न किए जा सकते हैं। यह higher-order फ़ंक्शन्स जैसे sorted(key=...), map(), और filter() की नींव है।

एक फ़ंक्शन एक ऑब्जेक्ट है जिसे आप संदर्भ से पास करते हैं, कभी नहीं एक कॉपी, इसलिए एक को दूसरे फ़ंक्शन को हाथ देना सस्ता है। पैटर्न जो इससे बढ़ता है क्लोज़र है: एक फ़ंक्शन दूसरे के अंदर परिभाषित जो अभी भी बाहरी फ़ंक्शन के वेरिएबल्स को पहुँचता है बाहरी एक रिटर्न करने के बाद। यह है कि कैसे आप उड़ान पर एक कॉन्फ़िगर किए गए फ़ंक्शन बनाते हैं, एक make_multiplier(3) जो 3 से गुणा करने वाला फ़ंक्शन रिटर्न करता है, 3 को कैप्चर किए और रखे जाने के साथ। वास्तविक कोड में दो सावधानियां: एक क्लोज़र वेरिएबल को कैप्चर करता है, कैप्चर समय पर इसकी वैल्यू नहीं, जो लोगों को एक लूप में क्लोज़र्स बनाने में पकड़ता है (वे सभी लूप की अंतिम वैल्यू देखते हैं); और कई रिटर्न किए गए फ़ंक्शन्स को स्टैक करना कॉल पाथ को ट्रेस करना कठिन बनाता है, इसलिए जहाँ वे स्पष्ट रूप से पढ़ते हैं वहाँ क्लोज़र्स का उपयोग करें और अवस्था बढ़ने पर एक क्लास तक पहुँचें।

python
def double(x):
    return x * 2

def apply(func, value):
    return func(value)

apply(double, 5)   # 10

फ़ंक्शन्स को आर्गुमेंट्स के रूप में पास करना sorted(), map(), और filter() के साथ लगातार दिखाई देता है। आप इसे Lambdas and comprehensions अध्याय में भी देखेंगे।

Junoफ़ंक्शन्स को वैल्यूज़ के रूप में एक फ़ंक्शन एक वैल्यू है, एक स्ट्रिंग या संख्या की तरह, इसलिए आप इसे एक वेरिएबल में स्टोर कर सकते हैं और इसे दूसरे फ़ंक्शन को दे सकते हैं। यही वह है जो आपको एक `key=` के रूप में `sorted()` को एक फ़ंक्शन पास करने देता है। मुझे शुरुआत में यह अजीब लगा, फिर यह क्लिक हुआ और हर जगह दिखाई दिया।
Junoफ़ंक्शन्स को वैल्यूज़ के रूप में फ़ंक्शन्स first-class ऑब्जेक्ट्स हैं: उन्हें असाइन करें, एक लिस्ट में स्टोर करें, पास करें, रिटर्न करें। यह `sorted(key=...)`़, `map()` और `filter()` के पीछे इंजन है, और हर कॉलबैक के पीछे जिसे आप बाद में वायर करेंगे।
Junoफ़ंक्शन्स को वैल्यूज़ के रूप में एक फ़ंक्शन को पास करना एक संदर्भ है, कॉपी नहीं, और एक क्लोज़र एक आंतरिक फ़ंक्शन को बाहरी के वेरिएबल्स को पहुँचने देता है इसके रिटर्न करने के बाद। यह वेरिएबल को कैप्चर करता है, वैल्यू नहीं, इसलिए एक लूप में क्लोज़र्स बनाना हर बार काटता है। जब कैप्चर की गई अवस्था बढ़े, एक क्लास बेहतर पढ़ता है।

व्यावहारिक में

दो फ़ंक्शन्स जो एक साथ काम करते हैं: letter_grade एक स्कोर को एक अक्षर में परिवर्तित करता है, और summarise इसे एक लिस्ट में हर स्कोर के लिए कॉल करता है:

python
def letter_grade(score: int) -> str:
    if score >= 90:
        return "A"
    elif score >= 80:
        return "B"
    elif score >= 70:
        return "C"
    else:
        return "F"

def summarise(scores: list[int]) -> None:
    total = sum(scores)
    avg = total / len(scores)
    grades = []
    for s in scores:
        grades.append(letter_grade(s))
    print(f"Average: {avg:.1f}")
    print(f"Grades: {', '.join(grades)}")

summarise([87, 92, 74, 65, 91])

एक लॉग फॉर्मेटर और एक फ़ाइल प्रोसेसर जो इसे उपयोग करता है, एक dry_run डिफ़ॉल्ट पैरामीटर के साथ जो साइड इफेक्ट्स को रोकता है जब तक स्पष्ट रूप से अक्षम न किया जाए:

python
def format_log(level: str, message: str) -> str:
    return f"[{level.upper():5}] {message}"

def process_file(path: str, dry_run: bool = True) -> bool:
    print(format_log("info", f"Processing {path}"))
    if dry_run:
        print(format_log("info", "Dry run, no changes made"))
        return True
    return True

process_file("report.csv")
process_file("report.csv", dry_run=False)

एक single-value नॉर्मेलाइज़र और एक कॉलम नॉर्मेलाइज़र इसके शीर्ष पर बनाया गया, टाइप हिंट्स और एक डॉकस्ट्रिंग के साथ। कॉलम फ़ंक्शन रेंज को एक बार गणना करता है और हर वस्तु के लिए स्केलर फ़ंक्शन का पुनः उपयोग करता है:

python
def normalise(value: float, min_val: float, max_val: float) -> float:
    """दिए गए न्यूनतम और अधिकतम के अनुसार वैल्यू को 0-1 रेंज में स्केल करें।"""
    if max_val == min_val:
        return 0.0
    return (value - min_val) / (max_val - min_val)

def normalise_column(values: list[float]) -> list[float]:
    """वैल्यूज़ के पूरे कॉलम को नॉर्मेलाइज़ करें।"""
    lo, hi = min(values), max(values)
    return [normalise(v, lo, hi) for v in values]

raw = [10.0, 25.0, 5.0, 40.0, 15.0]
print(normalise_column(raw))

टाइप हिंट्स यहाँ दो उद्देश्य परोसते हैं: वे डॉक्यूमेंट करते हैं कि फ़ंक्शन क्या अपेक्षा करता है, और वे एक टाइप चेकर को कॉलर्स को पकड़ने देते हैं जो गलती से एक स्ट्रिंग्स की लिस्ट पास करते हैं।