अध्याय 22

मॉड्यूल्स और इम्पोर्ट

अपनी लिखी फ़ाइल को दूसरी फ़ाइल से इस्तेमाल करना, import करने पर वास्तव में क्या होता है, `if __name__ == "__main__"` क्यों ज़रूरी है, स्टैंडर्ड लाइब्रेरी, और नाम के टकराव का जाल।

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

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

पिछले अध्याय में हमने एक line_total फ़ंक्शन लिखा था। अब एक दूसरे प्रोग्राम को उसी चीज़ की आवश्यकता है।

आसान तरीका इसे कॉपी करना है। यह पहले दिन काम करता है।

फिर टैक्स की दर बदल जाती है। आप एक फ़ाइल ठीक करते हैं और दूसरी भूल जाते हैं। अब दो प्रोग्राम एक ही ऑर्डर के लिए दो अलग-अलग योग दिखाते हैं, और यह कहना असंभव है कि कौन सा सही है — क्योंकि दोनों अपनी-अपनी फ़ाइल के अनुसार सही हैं।

समस्या कॉपी करने के प्रयास की नहीं है। समस्या यह है कि सत्य अब दो स्थानों पर रहता है।

python
import pricing

print(pricing.TAX_RATE)
print(pricing.line_total(15.0, 3))
text
0.15
51.75

एक फ़ाइल, और जितने चाहें उतने प्रोग्राम उसका उपयोग कर सकते हैं। जब दर बदलती है, तो यह एक ही स्थान पर बदलती है।

यह अध्याय उसी एक पंक्ति — import — और इसके पीछे वास्तव में क्या होता है, इसके बारे में है।

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

  • अपनी लिखी फ़ाइल को दूसरी फ़ाइल से इम्पोर्ट करना
  • import x, from x import y और import x as z के बीच अंतर बताना
  • यह जानना कि इम्पोर्ट के समय वास्तव में क्या होता है, और यह कितनी बार होता है
  • यह समझाना कि if __name__ == "__main__": क्यों लिखा जाता है
  • स्टैंडर्ड लाइब्रेरी से मॉड्यूल्स लाना
  • यह जानना कि पायथन कहाँ खोजता है, और अपने नाम की फ़ाइल से किसी मॉड्यूल को छिपाने से बचना

पूर्वापेक्षाएँ: स्कोप और म्युटेबल डिफ़ॉल्ट्स.


एक मॉड्यूल केवल एक फ़ाइल है

pricing.py नामक फ़ाइल एक मॉड्यूल है जिसे pricing कहा जाता है। कुछ भी घोषित करने की आवश्यकता नहीं है — फ़ाइल का होना ही पर्याप्त है।

import pricing पूरे मॉड्यूल को अंदर लाता है, और इसके अंदर की चीज़ों तक डॉट के माध्यम से पहुँचा जाता है: pricing.TAX_RATE, pricing.line_total(...)।

डॉट अतिरिक्त टाइपिंग जैसा लग सकता है, लेकिन यह एक काम करता है — पढ़ते समय यह बताता है कि चीज़ कहाँ से आई है।

केवल वही लाना जिसकी आपको आवश्यकता है

python
from pricing import line_total

print(line_total(15.0, 3))
print(TAX_RATE)
text
51.75
NameError: name 'TAX_RATE' is not defined

from ... import ... केवल वही नाम लाता है जो माँगा गया था, और उस नाम का सीधे उपयोग किया जाता है।

लेकिन अन्य नाम नहीं आते। TAX_RATE नहीं माँगा गया था, इसलिए यह यहाँ उपलब्ध नहीं है।

किसे इस्तेमाल करें? संक्षेप में: जब आपको दो या तीन नामों की आवश्यकता हो तो from, जब आपको कई नामों की आवश्यकता हो तो पूरा मॉड्यूल। और एक चीज़ कभी न करें — from pricing import *। यह चुपचाप हर नाम को खींच लेता है।

इम्पोर्ट करते समय नाम बदलना — as

python
import pricing as p

print(p.line_total(15.0, 3))
text
51.75

as मॉड्यूल को इस फ़ाइल के अंदर एक छोटा नाम देता है।

इम्पोर्ट करने का मतलब है फ़ाइल चलाना

tools.py:

python
print("tools is being set up")


def ping():
    return "pong"

main.py:

python
print("main starts")
import tools
import tools

print(tools.ping())
print("main ends")
text
main starts
tools is being set up
pong
main ends

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

इम्पोर्ट करने का मतलब है फ़ाइल को ऊपर से नीचे तक चलाना। def पंक्तियाँ फ़ंक्शन बनाती हैं, और बाकी सब कुछ वास्तव में निष्पादित होता है। मॉड्यूल के शीर्ष स्तर पर print या input रखने से यह उसे इम्पोर्ट करने वाले प्रत्येक व्यक्ति पर चलता है।

दूसरे import tools ने कुछ नहीं किया। एक मॉड्यूल प्रति प्रोग्राम केवल एक बार चलता है; उसके बाद पायथन वही लौटा देता है जो उसके पास पहले से है।

__name__ और वह प्रसिद्ध पंक्ति

प्रत्येक मॉड्यूल के अंदर __name__ नामक एक चर होता है, जिसे पायथन स्वयं सेट करता है।

tools.py:

python
def ping():
    return "pong"


print("module name is", __name__)

if __name__ == "__main__":
    print("running directly")

नियम सरल है: जिस फ़ाइल को आप सीधे चला रहे हैं उसका __name__ "__main__" होता है; जिन फ़ाइलों को इम्पोर्ट किया जा रहा है उनका नाम उनका अपना मॉड्यूल नाम होता है।

इसलिए if __name__ == "__main__": के अंदर जो कुछ भी है वह केवल तब चलता है जब फ़ाइल सीधे चलाई जाती है, कभी तब नहीं जब इसे इम्पोर्ट किया जाता है।

स्टैंडर्ड लाइब्रेरी (Standard Library)

पायथन के साथ कई मॉड्यूल्स पहले से आते हैं:

python
import math
import statistics

print(math.sqrt(144))
print(math.floor(3.7), math.ceil(3.2))
print(statistics.mean([10, 20, 60]))
text
12.0
3 4
30

एक और जो अक्सर उपयोग होता है:

python
import random

random.seed(7)
print(random.randint(1, 100))
print(random.choice(["pen", "bag", "ink"]))
text
42
pen

random.seed(7) के बिना प्रत्येक रन अलग-अलग संख्याएँ देगा। एक सीड (seed) सेट करना क्रम को स्थिर कर देता है, ताकि परिणाम दोहराए जा सकें।

पायथन कहाँ खोजता है

import pricing के लिए, पायथन क्रम में खोजता है: पहले इंटरप्रेटर में निर्मित मॉड्यूल्स, फिर स्क्रिप्ट का फ़ोल्डर, फिर स्टैंडर्ड लाइब्रेरी, फिर इंस्टॉल किए गए पैकेज।

नियम: कभी भी किसी फ़ाइल का नाम किसी मॉड्यूल के नाम पर न रखें। random.py, string.py, json.py, csv.py — यदि आप अपने फ़ोल्डर में random.py बनाते हैं, तो import random आपकी फ़ाइल को लोड करेगा न कि पायथन के असली मॉड्यूल को!


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

तीन फाइलें:

pricing.py:

python
"""कीमतें और टैक्स। यहाँ कुछ भी प्रिंट नहीं होता है, और न ही इनपुट माँगा जाता है।"""

TAX_RATE = 0.15


def line_total(price, quantity):
    """ऑर्डर की एक पंक्ति, टैक्स सहित।"""
    return round(price * quantity * (1 + TAX_RATE), 2)


def order_total(lines):
    """`lines` (name, price, quantity) टपल्स की एक सूची है।"""
    return round(sum(line_total(price, qty) for _, price, qty in lines), 2)

report.py:

python
"""संख्याओं को टेक्स्ट की पंक्तियों में बदलना।"""

import pricing


def receipt(lines):
    rows = [f"{name:<8} {pricing.line_total(price, qty):>8.2f}"
            for name, price, qty in lines]
    rows.append("-" * 17)
    rows.append(f"{'total':<8} {pricing.order_total(lines):>8.2f}")
    return rows


if __name__ == "__main__":
    print("report.py has no data of its own to show")

main.py:

python
"""एकमात्र फ़ाइल जिसे सीधे चलाने के लिए बनाया गया है।"""

import statistics

from report import receipt

ORDER = [
    ("pen", 15.0, 3),
    ("bag", 850.0, 1),
    ("ink", 120.0, 2),
]


def main():
    for row in receipt(ORDER):
        print(row)

    print()
    quantities = [qty for _, _, qty in ORDER]
    print("mean quantity:", statistics.mean(quantities))


if __name__ == "__main__":
    main()

python main.py चलाने पर:

text
pen         51.75
bag        977.50
ink        276.00
-----------------
total     1305.25

mean quantity: 2

जब यह टूटता है

ModuleNotFoundError: No module named 'priceing' गलत वर्तनी, या फ़ाइल दूसरे फ़ोल्डर में है।

ImportError: cannot import name 'line_totl' from 'pricing' मॉड्यूल मिल गया, लेकिन उसके अंदर का नाम नहीं मिला।

AttributeError: module 'random' has no attribute 'choice' लगभग हमेशा आपकी बनाई कोई फ़ाइल असली मॉड्यूल को छिपा रही होती है। अपने फ़ोल्डर में उस नाम की फ़ाइल ढूंढें और उसका नाम बदलें।

ImportError: circular import दो फ़ाइलें एक-दूसरे को इम्पोर्ट कर रही हैं। दोनों को जो चाहिए उसे एक तीसरी फ़ाइल में ले जाएं।