The Story That Explains Modules and Packages 🧰Modules और Packages समझाने वाली कहानी 🧰一个讲清模块与包的故事 🧰
Soon you need saws, chisels and drills. You gather them into a toolbox — one container that keeps related tools together so you can carry them as a unit. That is a module: one
.py file that bundles related functions, classes and constants.Then you take jobs all over town. One toolbox is not enough — you need a van with labelled drawers: electrics, plumbing, framing. Each drawer is a toolbox of its own, and the van holds them all. That is a package: a folder of modules, organised so things are easy to find.
And when you hire a helper, you don't rebuild your tools — you say "grab the drill from the blue drawer." That is an
import statement.जल्द ही आपको आरी, छेनी और drill चाहिए। आप उन्हें एक औज़ारों के डिब्बे में रखते हैं — एक container जो संबंधित औज़ारों को साथ रखता है ताकि उन्हें एक इकाई की तरह उठाया जा सके। यह है module: एक
.py file जो संबंधित functions, classes और constants को साथ बाँधती है।फिर आप पूरे शहर में काम लेते हैं। एक डिब्बा काफ़ी नहीं — आपको लेबल लगे दराज़ों वाली van चाहिए: बिजली, plumbing, ढाँचा। हर दराज़ अपने-आप में एक डिब्बा है, और van सबको रखती है। यह है package: modules का एक folder, इस तरह सजाया गया कि चीज़ें आसानी से मिलें।
और जब आप किसी सहायक को रखते हैं, तो अपने औज़ार दोबारा नहीं बनाते — आप कहते हैं "नीले दराज़ से drill ले आओ।" यही है
import statement।很快你需要锯子、凿子和电钻。你把它们装进一个 工具箱 — 一个把相关工具放在一起、可以整体搬运的容器。这就是 模块:一个把相关函数、类和常量打包在一起的
.py 文件。后来你在全城接活。一个工具箱不够了 — 你需要一辆带标签抽屉的 货车:电工、水管、木构。每个抽屉本身就是一个工具箱,货车装下所有抽屉。这就是 包:一个由模块组成、便于查找的文件夹。
当你雇了帮手,你不会重新造工具 — 你只说 "去蓝色抽屉拿电钻。"这就是
import 语句。A module is a single Python file. A package is a folder of modules. The import statement is how one file borrows code from another. These three ideas let you grow from one script to a whole system.
Module एक Python file है। Package modules का एक folder है। import statement वह तरीका है जिससे एक file दूसरी से code उधार लेती है। ये तीन विचार आपको एक script से पूरे system तक ले जाते हैं।
模块 是一个 Python 文件。包 是由模块组成的文件夹。import 语句是一个文件向另一个文件借用代码的方式。这三个概念让你从一个脚本成长为一整个系统。
The same .py file can be a script (when you run it) or a module (when another file imports it). A package groups modules in a folder.
वही .py file script हो सकती है (जब आप उसे चलाएँ) या module (जब दूसरी file उसे import करे)। Package modules को एक folder में समूह बनाता है।
同一个 .py 文件既可以是脚本(你运行它时),也可以是模块(被别的文件导入时)。包把模块组织在一个文件夹里。
Every Python file already is a module — you don't declare anything. The moment you save it, another file in the right place can import it. A package is a folder, usually with an __init__.py file inside that marks it as a package. That is the whole model.
हर Python file पहले से ही एक module है — आपको कुछ घोषित नहीं करना। Save करते ही, सही जगह पर रखी दूसरी file उसे import कर सकती है। Package एक folder है, आमतौर पर उसके अंदर एक __init__.py file होती है जो उसे package के रूप में चिह्नित करती है। बस यही पूरा मॉडल है।
每个 Python 文件 本来就是 模块 — 不需要任何声明。一保存,放在合适位置的其他文件就能 import 它。包是一个文件夹,通常里面有一个 __init__.py 文件,标记它是包。整个模型就这么简单。
Look for the interactive boxes: the __name__ Tracer (Section 05), the Import Path Lab (10), the Search Path Walk (11) and the Circular Import Tracer (15). Each one is built from real Python runs on real files — even the line-by-line steps were recorded with Python's own tracer.
Interactive डिब्बे खोजें: __name__ Tracer (Section 05), Import Path Lab (10), Search Path Walk (11) और Circular Import Tracer (15)। हर एक असली files पर असली Python runs से बना है — line-by-line कदम भी Python के अपने tracer से दर्ज किए गए हैं।
请留意这些互动框:__name__ Tracer(第 05 节)、Import Path Lab(10)、Search Path Walk(11)和 Circular Import Tracer(15)。每一个都基于真实文件上的真实 Python 运行 — 连逐行步骤都是用 Python 自带的跟踪器记录的。
Script vs Module vs Package 🗂️Script बनाम Module बनाम Package 🗂️脚本、模块与包 🗂️
python file.py. It runs from top to bottom. Think of it as "the entry point" — the file that kicks everything off.python file.py से शुरू करते हैं। यह ऊपर से नीचे चलती है। इसे "entry point" समझें — वह file जो सब कुछ शुरू करती है।python file.py 启动的文件。从上到下运行。把它看作"入口" — 启动一切的那个文件。import module_name. Physically the same as a script; only its role differs.import module_name से। देखने में script जैसी; सिर्फ़ उसकी भूमिका अलग है।import module_name 提供 可复用代码 — 函数、类、常量 — 的文件。物理上与脚本相同,只是 角色 不同。__init__.py; without one, Python 3.3+ treats it as a "namespace package".__init__.py होती है; उसके बिना Python 3.3+ इसे "namespace package" मानता है।__init__.py;没有它时,Python 3.3+ 把它当作"命名空间包"。Your First Module — A 90-Second Walkthrough ⏱️आपका पहला Module — 90 सेकंड में ⏱️你的第一个模块 — 90 秒上手 ⏱️
The smallest possible module: two files in the same folder. Then run python main.py.
सबसे छोटा module: एक ही folder में दो files। फिर python main.py चलाएँ।
最小的模块:同一文件夹中的两个文件。然后运行 python main.py。
# math_tools.py
PI = 3.14159
def area_circle(radius):
return PI * radius ** 2
def area_square(side):
return side ** 2# main.py
import math_tools
print(math_tools.area_circle(5))
print(math_tools.area_square(4))
print(math_tools.PI)
That's it. Because math_tools.py sits in the same folder as the script you ran, import math_tools finds it. No configuration, no build step. Section 11 shows exactly where Python looks.
बस इतना ही। क्योंकि math_tools.py उसी folder में है जहाँ चलाई गई script है, import math_tools उसे ढूँढ लेता है। कोई configuration नहीं, कोई build step नहीं। Section 11 ठीक-ठीक दिखाता है कि Python कहाँ-कहाँ देखता है।
就这样。因为 math_tools.py 和你运行的脚本在同一个文件夹,import math_tools 就能找到它。不需要配置,也没有构建步骤。第 11 节会准确展示 Python 到哪些地方查找。
The Six Import Styles — Know All of Them 📥Import के छह तरीके — सब जानें 📥六种导入写法 — 全都要会 📥
# 1) Import the whole module - use it with a dot
import math
print(math.sqrt(16))
# 2) Import with an alias - handy for long names (numpy is installed with pip)
import numpy as np
print(np.array([1, 2, 3]) * 2)
# 3) Import specific names - no dot needed
from math import sqrt, pi
print(sqrt(16), pi)
# 4) Import a name with an alias
from datetime import date as dt
print(dt(2026, 1, 26).strftime("%d %b %Y"))
# 5) Import everything - avoid outside quick experiments
from math import *
print(floor(7.9)) # works, but where did floor come from?
# 6) Import from a module inside a package
from os.path import join
print(join("data", "file.csv"))
Style 2 uses numpy, a third-party package — install it first with python -m pip install numpy (Section 14). All the others are in the standard library.
तरीका 2 numpy इस्तेमाल करता है, जो third-party package है — पहले python -m pip install numpy से install करें (Section 14)। बाक़ी सब standard library में हैं।
写法 2 用到第三方包 numpy — 先用 python -m pip install numpy 安装(第 14 节)。其余都在标准库里。
| Styleतरीका写法 | Best forकिसके लिए अच्छा最适合 | Watch out forध्यान रखें注意 |
|---|---|---|
import x | Clear origin — you always see x.func()साफ़ स्रोत — हमेशा x.func() दिखता है来源清晰 — 总能看到 x.func() | Long module names get wordyलंबे module नाम भारी लगते हैं模块名长时显得啰嗦 |
import x as y | Long names (numpy, pandas) or clashesलंबे नाम (numpy, pandas) या टकराव长名字(numpy、pandas)或名字冲突 | Use the standard aliases (np, pd)मानक aliases इस्तेमाल करें (np, pd)使用通行别名(np、pd) |
from x import a | Names you use a lot; short callsबार-बार इस्तेमाल होने वाले नाम; छोटी calls常用的名字;调用更短 | Loses the "which module is this from?" hint"यह किस module से है?" का संकेत खो जाता है失去"它来自哪个模块?"的提示 |
from x import a as b | Renaming to avoid a clashटकराव से बचने के लिए नाम बदलना改名以避免冲突 | Confuses readers unless the alias is commonAlias आम न हो तो पढ़ने वाले उलझते हैं别名不常见时会让读者困惑 |
from x import * | Quick experiments in the REPL onlyसिर्फ़ REPL में जल्दी के प्रयोग仅限 REPL 中快速试验 | Silently overwrites names (see below)चुपचाप नाम overwrite करता है (नीचे देखें)悄悄覆盖名字(见下文) |
from x.y import a | Reaching into a packagePackage के अंदर पहुँचना深入包内部 | Very deep paths suggest poor package designबहुत गहरे paths ख़राब package design का संकेत路径太深说明包设计欠佳 |
Why from module import * Is Risky — Prooffrom module import * जोखिम भरा क्यों — सबूत为什么 from module import * 有风险 — 证明
def process(data):
return [x.strip() for x in data]def process(data):
return sum(data)from cleaning import *
from billing import * # silently replaces process!
print(process.__module__)
print(process([" a ", " b "]))
Both modules define process(). The second star import silently replaced the first — no warning — so the cleaning code ended up calling the billing function and crashed. With explicit imports (import cleaning, then cleaning.process()) this can't happen, and a code search finds every use.
दोनों modules process() बनाते हैं। दूसरे star import ने पहले वाले को चुपचाप बदल दिया — कोई चेतावनी नहीं — इसलिए सफ़ाई वाले code ने billing function बुला दिया और crash हुआ। Explicit imports (import cleaning, फिर cleaning.process()) में ऐसा नहीं हो सकता, और code search हर इस्तेमाल ढूँढ लेता है।
两个模块都定义了 process()。第二个星号导入悄悄替换了第一个 — 没有任何警告 — 于是清洗代码调用了计费函数并崩溃。使用显式导入(import cleaning,再 cleaning.process())就不会这样,代码搜索也能找到每一处用法。
The if __name__ == "__main__" Idiom 🚪if __name__ == "__main__" का मुहावरा 🚪if __name__ == "__main__" 惯用法 🚪
Every module has a variable called __name__. When you run a file directly, its __name__ is "__main__". When you import it, __name__ is the module's name. This one difference lets a file be both a script and a module. Here is one file, run in two different ways:
हर module में __name__ नाम का variable होता है। जब आप file को सीधे चलाते हैं, उसका __name__ "__main__" होता है। जब आप उसे import करते हैं, __name__ module का नाम होता है। यही एक फ़र्क़ file को script और module दोनों बनने देता है। यह एक file है, दो अलग तरीकों से चलाई गई:
每个模块都有一个名为 __name__ 的变量。直接 运行 文件时,它的 __name__ 是 "__main__";被 导入 时,__name__ 是模块名。正是这一点区别,让一个文件既能当脚本 又能 当模块。下面是同一个文件的两种运行方式:
# math_tools.py
def area_circle(radius):
return 3.14159 * radius ** 2
def demo():
print("Testing area_circle:")
print(area_circle(5))
print(area_circle(10))
print("__name__ is", repr(__name__))
# This block ONLY runs when you execute the file directly
if __name__ == "__main__":
demo()import math_tools
print("main.py got", math_tools.area_circle(2))
python math_tools.py — __name__ is "__main__", so the demo runs.
python math_tools.py — __name__ "__main__" है, इसलिए demo चलता है।
python math_tools.py — __name__ 是 "__main__",所以演示代码运行。
import math_tools — __name__ is "math_tools", so the demo does not run. The top-level print still runs!
import math_tools — __name__ "math_tools" है, इसलिए demo नहीं चलता। Top-level print फिर भी चलता है!
import math_tools — __name__ 是 "math_tools",所以演示代码 不 运行。但顶层的 print 仍会运行!
Try It — __name__ Tracerकरके देखें — __name__ Tracer动手试试 — __name__ 跟踪器
Choose how the file is started, and whether it has the guard. Step through and watch which lines Python actually runs — the steps were recorded line by line with Python's tracer. Try no guard + imported to see the problem the guard solves.
चुनें कि file कैसे शुरू होती है, और उसमें guard है या नहीं। कदम-दर-कदम चलें और देखें Python असल में कौन-सी lines चलाता है — कदम Python के tracer से line-by-line दर्ज किए गए हैं। Guard किस समस्या को हल करता है, यह देखने के लिए no guard + imported आज़माएँ।
选择文件的启动方式,以及是否有守卫。逐步执行,看 Python 实际运行了哪些行 — 这些步骤是用 Python 跟踪器逐行记录的。试试 no guard + imported,看看守卫解决的是什么问题。
Without the guard, all top-level code runs the moment another file imports yours: tests, prints, slow setup. The guard says "only run this if I am the program being launched." It is how libraries stay quiet when imported. Keep the top level of a module to definitions — functions, classes, constants.
Guard के बिना, जैसे ही दूसरी file आपकी file import करती है, सारा top-level code चल जाता है: tests, prints, धीमी तैयारी। Guard कहता है "इसे तभी चलाओ जब मैं ही शुरू किया गया program हूँ।" इसी से libraries import होने पर चुप रहती हैं। Module के top level पर सिर्फ़ परिभाषाएँ रखें — functions, classes, constants।
没有守卫,别的文件一导入你的文件,所有顶层代码就会运行:测试、打印、缓慢的初始化。守卫的意思是 "只有我是被启动的那个程序时才运行这段。"库就是靠它在被导入时保持安静。模块顶层只放定义 — 函数、类、常量。
Imports Run Once — The Module Cache 🗄️Import एक ही बार चलता है — Module Cache 🗄️导入只运行一次 — 模块缓存 🗄️
The first import of a module runs its file and stores the module object in a dictionary called sys.modules. Every later import of the same name just looks it up there — the file is not run again.
किसी module का पहला import उसकी file चलाता है और module object को sys.modules नाम की dictionary में रख देता है। उसी नाम का हर अगला import बस वहाँ देखता है — file दोबारा नहीं चलती।
首次 import 某个模块时,会运行它的文件,并把模块对象存进名为 sys.modules 的字典。之后再导入同名模块,只是在那里查找 — 文件 不会 再次运行。
print(" ...loading noisy.py")
COUNT = 0import sys
import importlib
import noisy
import noisy # second import: nothing printed
noisy.COUNT += 1
print("noisy" in sys.modules)
print(noisy.COUNT)
importlib.reload(noisy) # force a fresh run of the file
print(noisy.COUNT)
Importing is cheap after the first time, and every file that imports noisy shares the same module object — a change made through one import (like COUNT += 1) is seen by all of them. importlib.reload() runs the file again, which is handy in an interactive session but rarely needed in programs.
पहली बार के बाद import सस्ता है, और noisy import करने वाली हर file एक ही module object साझा करती है — एक import से किया गया बदलाव (जैसे COUNT += 1) सभी को दिखता है। importlib.reload() file को फिर से चलाता है, जो interactive session में काम का है पर programs में कम ही चाहिए।
第一次之后导入就很便宜,而且每个导入 noisy 的文件共享 同一个 模块对象 — 通过一处导入所做的修改(如 COUNT += 1)所有人都能看到。importlib.reload() 会重新运行文件,在交互式会话中很方便,但程序里很少需要。
Packages — Modules Grow Up 📦Packages — Modules बड़े होते हैं 📦包 — 模块长大了 📦
When one file grows into ten, group them in a folder — a package. Packages let you organise code by feature, share it between projects and publish libraries.
जब एक file दस बन जाए, तो उन्हें एक folder में रखें — एक package। Packages से आप code को feature के हिसाब से सजा सकते हैं, projects में साझा कर सकते हैं और libraries publish कर सकते हैं।
当一个文件长成十个,就把它们放进一个文件夹 — 包。包让你按功能组织代码、在项目间共享、发布库。
Amber folders are packages, ⚙️ files are __init__.py markers, blue files are ordinary modules.
नारंगी folders packages हैं, ⚙️ files __init__.py markers हैं, नीली files सामान्य modules हैं।
琥珀色文件夹是包,⚙️ 文件是 __init__.py 标记,蓝色文件是普通模块。
__init__.py Required?क्या __init__.py ज़रूरी है?__init__.py 是必需的吗?Since Python 3.3, a folder without __init__.py can still be imported — it becomes a namespace package, a feature meant for splitting one package across several folders. For your own projects, add an __init__.py (it can be empty): it makes the folder a regular package, and many tools expect it.
Python 3.3 से, __init__.py के बिना folder भी import हो सकता है — वह namespace package बन जाता है, यह feature एक package को कई folders में बाँटने के लिए है। अपने projects में __init__.py ज़रूर रखें (ख़ाली भी चलेगी): इससे folder सामान्य package बनता है, और कई tools इसकी उम्मीद करते हैं।
从 Python 3.3 起,没有 __init__.py 的文件夹也能被导入 — 它成为 命名空间包,这个特性用于把一个包拆分到多个文件夹。在自己的项目里请加上 __init__.py(可以为空):它让文件夹成为普通包,很多工具也依赖它。
Importing from a Package — Dotted Paths 🔗Package से Import — Dots वाले Paths 🔗从包中导入 — 点号路径 🔗
Inside a package, import uses dots to walk down the folders: each dot goes one level deeper. This main.py sits next to the mypackage/ folder from the diagram above:
Package के अंदर import folders में नीचे जाने के लिए dots इस्तेमाल करता है: हर dot एक स्तर गहरा जाता है। यह main.py ऊपर के चित्र वाले mypackage/ folder के बगल में है:
在包里,import 用 点号 逐级进入文件夹:每个点深入一层。下面的 main.py 与上图的 mypackage/ 文件夹位于同一层:
# main.py - OUTSIDE the package
import mypackage.config
print(mypackage.config.DEBUG)
import mypackage.core.engine
print(mypackage.core.engine.run())
from mypackage.core import engine
print(engine.run())
from mypackage.core.engine import run
print(run())
from mypackage.core import engine as eng
print(eng.run())
The __init__.py File — What Goes in It? 🎁__init__.py File — इसमें क्या जाता है? 🎁__init__.py 文件 — 里面放什么?🎁
Most __init__.py files are empty. But __init__.py runs the first time the package is imported, so it is the perfect place to shape the package's public face: re-export the useful names and list them in __all__.
ज़्यादातर __init__.py files ख़ाली होती हैं। पर package के पहली बार import होने पर __init__.py चलती है, इसलिए यह package का सार्वजनिक चेहरा बनाने की बढ़िया जगह है: काम के नाम re-export करें और उन्हें __all__ में लिखें।
大多数 __init__.py 是空的。但包第一次被导入时 __init__.py 会运行,所以它是塑造包的 公开门面 的好地方:重新导出有用的名字,并在 __all__ 中列出它们。
# shop/__init__.py - the public face of the package
from .cart import add_item, total, _audit
from .config import VERSION
__all__ = ["add_item", "total", "VERSION"]_items = []
def add_item(name, price):
_items.append((name, price))
def total():
return sum(price for _, price in _items)
def _audit():
return list(_items)from shop import add_item, total, VERSION # short, thanks to __init__.py
add_item("pen", 20)
add_item("book", 150)
print("total:", total(), "| version:", VERSION)
from shop.cart import total as deep_total # the long path still works
print(deep_total())
ns = {}
exec("from shop import *", ns) # what does * bring in?
print(sorted(k for k in ns if not k.startswith("__")))
__all__ and the Leading Underscore__all__ और आगे का Underscore__all__ 与前导下划线__all__ decides what from shop import * brings in — above, _audit stayed out. Without __all__, a star import skips every name that starts with _. Either way, nothing is truly private: from shop import _audit still works. A leading underscore is a polite signal — "internal, may change, don't rely on it."
__all__ तय करता है कि from shop import * क्या लाए — ऊपर _audit बाहर रहा। __all__ के बिना star import _ से शुरू होने वाला हर नाम छोड़ देता है। दोनों हालात में कुछ भी सच में private नहीं: from shop import _audit फिर भी चलता है। आगे का underscore एक विनम्र संकेत है — "अंदरूनी, बदल सकता है, इस पर निर्भर न रहें।"
__all__ 决定 from shop import * 会带进来什么 — 上面的 _audit 就没有被带进来。没有 __all__ 时,星号导入会跳过所有以 _ 开头的名字。无论哪种情况,都没有真正的私有:from shop import _audit 依然可用。前导下划线只是礼貌的信号 —"内部使用,可能会改,别依赖它。"
Absolute vs Relative Imports 🧭Absolute बनाम Relative Imports 🧭绝对导入与相对导入 🧭
When code inside a package imports another part of the same package, you can spell out the full path (absolute) or use dots relative to the current file (relative).
जब package के अंदर का code उसी package का दूसरा हिस्सा import करे, तो आप पूरा path लिख सकते हैं (absolute) या मौजूदा file के हिसाब से dots इस्तेमाल कर सकते हैं (relative)।
当包 内部 的代码导入 同一 包的其他部分时,你可以写出完整路径(绝对),也可以用相对当前文件的点号(相对)。
| Traitगुण特性 | Behaviourव्यवहार表现 |
|---|---|
| Syntax | from mypackage.core import utils |
| Reads likeऐसे पढ़ा जाता है读起来像 | A full addressपूरा पता完整地址 |
| Renaming the packagePackage का नाम बदलना包改名 | Every import must changeहर import बदलना पड़ता है每处导入都得改 |
| PEP 8 | Recommended by defaultDefault रूप से सुझाया गया默认推荐 |
| Traitगुण特性 | Behaviourव्यवहार表现 |
|---|---|
| Syntax | from . import utils |
| Reads likeऐसे पढ़ा जाता है读起来像 | "Next to me""मेरे बगल में""在我旁边" |
| Renaming the packagePackage का नाम बदलना包改名 | Keeps workingचलता रहता है仍然有效 |
| Ruleनियम规则 | Only inside a packageसिर्फ़ package के अंदर只能在包内使用 |
from . import utils
यही package — वह folder जिसमें यह file है: from . import utils
当前包 — 本文件所在的文件夹:from . import utils
foo in this package: from .utils import tidy
इसी package का module foo: from .utils import tidy
当前包中的模块 foo:from .utils import tidy
from .. import config
Parent package, एक स्तर ऊपर: from .. import config
父包,向上一级:from .. import config
foo in the parent package: from ..helpers import shout
Parent package का module foo: from ..helpers import shout
父包中的模块 foo:from ..helpers import shout
Here is engine.py using all three forms, started in two different ways:
यह engine.py तीनों रूप इस्तेमाल करती है, दो अलग तरीकों से शुरू की गई:
下面的 engine.py 用了全部三种写法,并以两种方式启动:
# mypackage/core/engine.py
from mypackage import config # 1) absolute
from . import utils # 2) relative, same package (core/)
from .. import helpers # 3) relative, parent package (mypackage/)
def run():
return "engine running"
if __name__ == "__main__":
print(config.VERSION, utils.tidy(" a b "), helpers.shout("go"))
-mPackage Modules को -m से चलाएँ用 -m 运行包中的模块Started by its path, engine.py is just a script: Python puts mypackage/core/ at the front of sys.path, so it can't see mypackage at all — even the absolute import fails, and relative imports would fail with attempted relative import with no known parent package. Run it from the project folder with python -m mypackage.core.engine and everything works.
Path से शुरू करने पर engine.py बस एक script है: Python mypackage/core/ को sys.path में सबसे आगे रखता है, इसलिए वह mypackage को देख ही नहीं पाता — absolute import भी fail होता है, और relative imports attempted relative import with no known parent package के साथ fail होते। Project folder से python -m mypackage.core.engine चलाएँ और सब चलता है।
按路径启动时,engine.py 只是个脚本:Python 把 mypackage/core/ 放在 sys.path 最前面,因此根本看不到 mypackage — 连 绝对 导入都失败,相对导入则会报 attempted relative import with no known parent package。在项目文件夹中用 python -m mypackage.core.engine 运行,一切正常。
Try It — Import Path Labकरके देखें — Import Path Lab动手试试 — 导入路径实验室
Choose who is importing, what it imports and which style it uses. Each of the 18 combinations was really run on these files — the console shows Python's actual result.
चुनें कौन import कर रहा है, क्या import करता है और कौन-सा तरीका इस्तेमाल करता है। 18 में से हर जोड़ इन files पर सच में चलाया गया — console Python का असली नतीजा दिखाता है।
选择谁在导入、导入什么、用哪种写法。18 种组合都在这些文件上真实运行过 — 控制台显示的是 Python 的实际结果。
How Python Finds a Module — The Search Path 🔎Python Module कैसे ढूँढता है — Search Path 🔎Python 如何找到模块 — 搜索路径 🔎
When you write import random, Python asks a fixed list of places, in order, and uses the first one that has it. The full order is:
जब आप import random लिखते हैं, Python जगहों की एक तय सूची से क्रम से पूछता है, और जिसके पास पहले मिले उसे इस्तेमाल करता है। पूरा क्रम यह है:
当你写 import random 时,Python 会 按顺序 询问一组固定的地方,用第一个找到的。完整顺序是:
Steps 4–7 are the folders in sys.path, in order. Your script's folder comes before the standard library — that is why a file called random.py can hide the real random.
कदम 4–7 sys.path के folders हैं, क्रम से। आपकी script का folder standard library से पहले आता है — इसीलिए random.py नाम की file असली random को छिपा सकती है।
第 4–7 步是 sys.path 中按顺序排列的文件夹。脚本所在文件夹排在标准库 之前 — 这就是名为 random.py 的文件能遮住真正 random 的原因。
Try It — Search Path Walkकरके देखें — Search Path Walk动手试试 — 搜索路径之旅
Pick a module, then add a local file with the same name, or a PYTHONPATH folder. Press Play and watch Python walk the list. Every result — including the real file path in the console — comes from actually running Python 3.13 in that situation. Compare random, math and os with a local file: only one of them gets hijacked!
एक module चुनें, फिर उसी नाम की local file, या PYTHONPATH folder जोड़ें। चलाएँ दबाएँ और Python को सूची में चलते देखें। हर नतीजा — console का असली file path भी — उस स्थिति में Python 3.13 को सच में चलाकर आया है। Local file के साथ random, math और os की तुलना करें: इनमें से सिर्फ़ एक ही hijack होता है!
选一个模块,再加上同名的本地文件或 PYTHONPATH 文件夹。点 播放,看 Python 沿列表查找。每个结果 — 包括控制台中的真实文件路径 — 都来自在该情境下实际运行 Python 3.13。比较一下带本地文件时的 random、math 和 os:只有一个会被劫持!
See Your Own Search Pathअपना Search Path देखें查看你自己的搜索路径
import sys
for path in sys.path:
print(path)
These are the folders on the machine that built this page — yours will differ, but the shape is the same: your project first, then the standard library, then the folders where pip installs packages.
ये उस मशीन के folders हैं जिसने यह page बनाया — आपके अलग होंगे, पर ढाँचा वही है: पहले आपका project, फिर standard library, फिर वे folders जहाँ pip packages install करता है।
这些是构建本页面的机器上的文件夹 — 你的会不同,但结构一样:先是你的项目,然后是标准库,最后是 pip 安装包的文件夹。
The Shadowing Trap — ProofShadowing का जाल — सबूत遮蔽陷阱 — 证明
# random.py - oops, same name as the standard library module
print("my random.py was loaded!")import random
print(random.randint(1, 6))
Older versions only said module 'random' has no attribute 'randint', which is baffling. Since Python 3.13 the message adds "consider renaming … since it has the same name as the standard library module". Still, the rule stands: never name your files random.py, json.py, email.py, test.py or after any package you use.
पुराने versions बस module 'random' has no attribute 'randint' कहते थे, जो उलझाने वाला है। Python 3.13 से संदेश में "consider renaming … since it has the same name as the standard library module" जुड़ता है। फिर भी नियम वही है: अपनी files के नाम कभी random.py, json.py, email.py, test.py या किसी इस्तेमाल होने वाले package पर न रखें।
旧版本只会说 module 'random' has no attribute 'randint',让人摸不着头脑。从 Python 3.13 起,信息里会加上 "consider renaming … since it has the same name as the standard library module"。但规则不变:永远不要把文件命名为 random.py、json.py、email.py、test.py,或你使用的任何包的名字。
Practical Example — Building a Small Package 🛠️व्यावहारिक उदाहरण — एक छोटा Package बनाना 🛠️实战示例 — 构建一个小包 🛠️
A real, minimal package for text analysis: four files, one clean public API. The folder looks like this:
Text analysis के लिए एक असली, छोटा package: चार files, एक साफ़ public API। Folder ऐसा दिखता है:
一个真实的、精简的文本分析包:四个文件,一个干净的公开 API。文件夹结构如下:
textstats/
__init__.py
_internal.py
counter.py
reader.py
speech.txt
main.py
# Internal helpers - the leading underscore says "private"
import re
def _clean(text):
"""Remove punctuation, lowercase, collapse spaces."""
text = re.sub(r"[^\w\s]", "", text.lower())
return " ".join(text.split())from collections import Counter
from ._internal import _clean # relative import - same package
def word_count(text):
"""Total words in a piece of text."""
return len(_clean(text).split())
def top_words(text, n=5):
"""The n most common words as (word, count) pairs."""
return Counter(_clean(text).split()).most_common(n)from pathlib import Path
def read_file(path):
"""Load the full text of a file."""
return Path(path).read_text(encoding="utf-8")# Expose the useful names at the package top level
from .counter import word_count, top_words
from .reader import read_file
__version__ = "1.0.0"
__all__ = ["word_count", "top_words", "read_file"]import textstats
text = textstats.read_file("speech.txt")
print(textstats.word_count(text))
print(textstats.top_words(text, n=3))
print(textstats.__version__)
You built a real, importable package in four small files. Users see three clean function names; _internal._clean() stays out of sight. Files inside textstats/ import each other with relative imports, so the package can be renamed without editing them. Big libraries like requests and numpy are organised the same way — just with more files.
आपने चार छोटी files में एक असली, import होने लायक package बनाया। Users को तीन साफ़ function नाम दिखते हैं; _internal._clean() नज़र से दूर रहता है। textstats/ के अंदर की files relative imports से एक-दूसरे को import करती हैं, इसलिए package का नाम उन्हें बदले बिना बदला जा सकता है। requests और numpy जैसी बड़ी libraries भी इसी तरह सजी हैं — बस ज़्यादा files के साथ।
你用四个小文件构建了一个真实、可导入的包。用户只看到三个干净的函数名;_internal._clean() 被隐藏起来。textstats/ 内的文件用相对导入互相引用,所以包改名时无需修改它们。requests、numpy 这样的大库也是这样组织的 — 只是文件更多。
The Standard Library — Modules You Already Have 📚Standard Library — Modules जो आपके पास पहले से हैं 📚标准库 — 你已经拥有的模块 📚
Python ships with hundreds of modules — "batteries included". Python itself can tell you how many:
Python सैकड़ों modules के साथ आता है — "batteries included"। Python ख़ुद बता सकता है कितने:
Python 自带数百个模块 —"自带电池"。Python 自己就能告诉你有多少:
import sys
print(len(sys.stdlib_module_names), "standard library modules")
print("json" in sys.stdlib_module_names, "requests" in sys.stdlib_module_names)
print(sys.builtin_module_names[:6])
| ModuleModule模块 | What it doesक्या करता है用途 | Exampleउदाहरण示例 |
|---|---|---|
os | Operating-system tasksOperating system के काम操作系统相关 | os.getcwd() |
sys | Interpreter details, command-line argumentsInterpreter की जानकारी, command-line arguments解释器信息、命令行参数 | sys.argv[1] |
pathlib | Modern file paths — prefer it to os.pathआधुनिक file paths — os.path से बेहतर现代文件路径 — 优先于 os.path | Path("data.csv").exists() |
datetime | Dates, times, time zonesतारीख़, समय, time zones日期、时间、时区 | datetime.now() |
json | Read and write JSONJSON पढ़ना और लिखना读写 JSON | json.loads(text) |
csv | Read and write CSV filesCSV files पढ़ना और लिखना读写 CSV 文件 | csv.reader(file) |
re | Regular expressionsRegular expressions正则表达式 | re.findall(r"\d+", text) |
collections | Counter, defaultdict, deque, namedtuple | Counter(words) |
itertools | Fast iterator building blocksतेज़ iterator औज़ार高效的迭代器工具 | chain, combinations |
functools | Tools for functionsFunctions के लिए औज़ार函数工具 | reduce, lru_cache |
random | Random numbers and samplingRandom संख्याएँ और sampling随机数与抽样 | random.choice(items) |
logging | Proper logging (better than print)सही logging (print से बेहतर)规范日志(优于 print) | logging.info("msg") |
argparse | Command-line optionsCommand-line options命令行参数解析 | parser.add_argument() |
unittest | Testing frameworkTesting framework测试框架 | class T(TestCase): |
Third-Party Packages — pip, requirements.txt and venv 🌐Third-Party Packages — pip, requirements.txt और venv 🌐第三方包 — pip、requirements.txt 与 venv 🌐
Beyond the standard library, more than half a million projects live on PyPI, the Python Package Index. You install them with pip. Writing python -m pip (instead of plain pip) guarantees that pip installs into the same Python you are running.
Standard library के आगे, पाँच लाख से ज़्यादा projects PyPI (Python Package Index) पर हैं। आप इन्हें pip से install करते हैं। python -m pip लिखना (सिर्फ़ pip की जगह) पक्का करता है कि pip उसी Python में install करे जो आप चला रहे हैं।
在标准库之外,PyPI(Python 包索引)上有五十多万个项目,用 pip 安装。写 python -m pip(而不是单纯的 pip)可以确保 pip 安装到你正在运行的那个 Python 里。
# Install a package
$ python -m pip install requests
# Install an exact version
$ python -m pip install "pandas==2.2.3"
# Save the exact versions you use, then reinstall them anywhere
$ python -m pip freeze > requirements.txt
$ python -m pip install -r requirements.txt
# List or remove packages
$ python -m pip list
$ python -m pip uninstall requests
Virtual Environments — Essential for Real ProjectsVirtual Environments — असली Projects के लिए ज़रूरी虚拟环境 — 真实项目的必需品
# Create an isolated environment for THIS project only
$ python -m venv .venv
# Activate it (macOS / Linux)
$ source .venv/bin/activate
# Activate it (Windows, PowerShell or cmd)
> .venv\Scripts\activate
# Now pip installs ONLY into this project
(.venv) $ python -m pip install requests pandas
# Leave the environment
(.venv) $ deactivate
Installing everything into one global Python leads to version fights: project A needs pandas 1.5, project B needs pandas 2.2, and only one can win. A virtual environment gives each project its own packages. Many Linux distributions and Homebrew Python now block global installs with an externally-managed-environment error (PEP 668) for exactly this reason — the fix is to create a venv, not to force it.
सब कुछ एक global Python में install करने से versions की लड़ाई होती है: project A को pandas 1.5 चाहिए, project B को pandas 2.2, और सिर्फ़ एक जीत सकता है। Virtual environment हर project को उसके अपने packages देता है। कई Linux distributions और Homebrew Python अब इसी वजह से global installs को externally-managed-environment error (PEP 668) से रोकते हैं — इलाज venv बनाना है, ज़बरदस्ती करना नहीं।
把所有东西装进同一个全局 Python 会导致版本冲突:项目 A 需要 pandas 1.5,项目 B 需要 pandas 2.2,只能有一个赢。虚拟环境为每个项目提供独立的包。正因如此,许多 Linux 发行版和 Homebrew 的 Python 现在会用 externally-managed-environment 错误(PEP 668)阻止 全局安装 — 正确做法是创建 venv,而不是强行安装。
Common Pitfalls — and the Circular Import 🔄आम गड्ढे — और Circular Import 🔄常见陷阱 — 以及循环导入 🔄
ImportError: cannot import name …. Fix: move shared code into a third module, or move one import inside a function.ImportError: cannot import name …। इलाज: साझा code को तीसरे module में ले जाएँ, या एक import को function के अंदर ले जाएँ।ImportError: cannot import name …。修复:把共享代码移到第三个模块,或把其中一个导入挪进函数内部。random.py is found before the real one, and everything that uses random breaks. Never name files after modules you use.random.py असली से पहले मिलती है, और random इस्तेमाल करने वाली हर चीज़ टूट जाती है। Files के नाम इस्तेमाल होने वाले modules पर कभी न रखें।random.py 先于真正的模块被找到,所有用到 random 的地方都会出错。永远不要用你所使用模块的名字给文件命名。python -m pkg.mod from the project folder.python -m pkg.mod से चलाएँ।python -m pkg.mod 运行包内的模块。A Circular Import, Step by Stepएक Circular Import, कदम-दर-कदम循环导入,一步一步看
# shop/users.py
from shop.orders import Order
class User:
pass# shop/orders.py
from shop.users import User # <- circular!
class Order:
passimport shop.users
Try It — Circular Import Tracerकरके देखें — Circular Import Tracer动手试试 — 循环导入跟踪器
Step through the broken version and the fixed one. Each step was recorded by Python's tracer while really running these files. Watch the sys.modules panel: a module is added the moment it starts loading — that half-loaded entry is the whole problem.
टूटा हुआ और ठीक किया हुआ version, दोनों कदम-दर-कदम चलाएँ। हर कदम इन files को सच में चलाते समय Python के tracer से दर्ज हुआ। sys.modules panel देखें: module तभी जुड़ जाता है जब वह load होना शुरू होता है — यही आधी-load हुई entry पूरी समस्या है।
逐步查看出错版本和修复版本。每一步都是在真实运行这些文件时由 Python 跟踪器记录的。注意 sys.modules 面板:模块在 开始 加载的那一刻就被加入 — 这个"加载了一半"的条目正是问题所在。
The Fix — Move Shared Code into a Third Moduleइलाज — साझा Code को तीसरे Module में ले जाएँ修复 — 把共享代码移到第三个模块
# models.py - shared types live here
class User:
def __init__(self, name):
self.name = name
class Order:
def __init__(self, user, item):
self.user, self.item = user, item# users.py
from models import User
def make_user(name):
return User(name)# orders.py
from models import Order
from users import make_user
def place(name, item):
return Order(make_user(name), item)from orders import place
o = place("Aarav", "notebook")
print(o.user.name, "ordered a", o.item)
When the two modules are loose files next to your script (not inside a package), Python 3.13 reports the same circular import with a misleading hint: "consider renaming … if it has the same name as a library you intended to import". The real cause is still the circle. Inside a package, as above, you get the clear message "partially initialized module … most likely due to a circular import".
जब दोनों modules आपकी script के बगल में खुली files हों (package के अंदर नहीं), तो Python 3.13 उसी circular import को भ्रामक संकेत के साथ बताता है: "consider renaming … if it has the same name as a library you intended to import"। असली वजह फिर भी circle ही है। Package के अंदर, जैसे ऊपर, आपको साफ़ संदेश मिलता है: "partially initialized module … most likely due to a circular import"।
当两个模块是脚本旁边的零散文件(不在包内)时,Python 3.13 报告同样的循环导入,却附带误导性提示:"consider renaming … if it has the same name as a library you intended to import"。真正的原因仍是循环。在包内(如上)你会得到清晰的信息:"partially initialized module … most likely due to a circular import"。
Golden Rules and Quick Quiz 🏆सुनहरे नियम और छोटा Quiz 🏆黄金法则与小测验 🏆
if __name__ == "__main__":. Keep the top level of a module to definitions, so importing it has no side effects.if __name__ == "__main__": से बचाएँ। Module के top level पर सिर्फ़ परिभाषाएँ रखें, ताकि import करने पर कोई side effect न हो।if __name__ == "__main__": 保护可运行代码。模块顶层只放定义,让导入没有副作用。from module import * outside quick REPL experiments. Explicit imports keep names traceable and prevent silent overwrites.from module import * से बचें। Explicit imports नामों का पता रखते हैं और चुपचाप overwrite होने से रोकते हैं।from module import *。显式导入让名字可追溯,防止悄悄覆盖。python -m package.module, from the project folder — never by their file path.python -m package.module से चलाएँ, project folder से — कभी उनके file path से नहीं।python -m package.module 运行包内模块 — 不要按文件路径运行。random.py, json.py, email.py, test.py. Your folder is searched before the standard library.random.py, json.py, email.py, test.py नहीं। आपका folder standard library से पहले खोजा जाता है।random.py、json.py、email.py、test.py。你的文件夹在标准库之前被搜索。requirements.txt. Install with python -m pip.requirements.txt में दर्ज करें। python -m pip से install करें।requirements.txt 中。用 python -m pip 安装。__all__. The underscore is a signal, not a lock.__all__ में लिखें। Underscore एक संकेत है, ताला नहीं।__all__ 中列出公开名字。下划线是信号,不是锁。Quick Quiz — 8 Questionsछोटा Quiz — 8 सवाल小测验 — 8 道题
A module is a file, a package is a folder, and import finds them by asking a fixed list of places — first match wins, and the result is cached in sys.modules. Guard script code with __name__, run package modules with -m, never shadow a library name, break import cycles with a shared module, and give every project its own virtual environment.
Module एक file है, package एक folder, और import उन्हें जगहों की एक तय सूची से पूछकर ढूँढता है — पहला match जीतता है, और नतीजा sys.modules में cache होता है। Script code को __name__ से बचाएँ, package modules को -m से चलाएँ, किसी library का नाम कभी न ढकें, import cycles को साझा module से तोड़ें, और हर project को उसका अपना virtual environment दें।
模块是一个文件,包是一个文件夹,import 通过询问一组固定的位置找到它们 — 第一个匹配获胜,结果缓存在 sys.modules 中。用 __name__ 保护脚本代码,用 -m 运行包内模块,永远不要遮蔽库名,用共享模块打破导入循环,并为每个项目准备独立的虚拟环境。