The Story That Explains Comprehensions 🧃Comprehensions समझाने वाली कहानी 🧃一个讲清推导式的故事 🧃
Option A — the old kitchen way: grab an empty crate. Pick up apple #1, wash it, slice it, drop it in the crate. Pick up apple #2, repeat. Four lines of instructions for something simple.
Option B — the assembly line: "Every apple on this counter, washed and pressed, into that crate — go." One sentence. Same result.
That is the difference between a for loop and a comprehension. Same output — one is a recipe, the other is a description of the result.
रास्ता A — पुरानी रसोई का तरीका: एक ख़ाली टोकरी लो। सेब #1 उठाओ, धोओ, काटो, टोकरी में डालो। सेब #2 उठाओ, दोहराओ। एक आसान काम के लिए चार lines के निर्देश।
रास्ता B — assembly line: "इस counter का हर सेब, धोकर और निचोड़कर, उस टोकरी में — शुरू करो।" एक वाक्य। वही नतीजा।
यही फ़र्क़ है for loop और comprehension में। Output एक जैसा — एक रेसिपी है, दूसरा नतीजे का वर्णन।
选项 A — 老厨房的做法:拿一个空箱子。拿起苹果 #1,洗、切、放进箱子。拿起苹果 #2,重复。为一件简单的事写了四行指令。
选项 B — 流水线:"把柜台上的每个苹果洗好榨好,放进那个箱子 — 开始。"一句话,结果相同。
这就是 for 循环 与 推导式 的区别。输出一样 — 一个是菜谱,另一个是对结果的描述。
A comprehension is Python's way of building a new collection — a list, dict or set — from an existing iterable in one readable expression. It replaces the classic "make an empty container → loop → append" pattern with one line that reads almost like English.
Comprehension Python का तरीका है जिससे किसी मौजूदा iterable से एक नया collection — list, dict या set — एक पढ़ने लायक expression में बनाया जाता है। यह पुराने "ख़ाली container बनाओ → loop → append" pattern की जगह एक line देता है जो लगभग अंग्रेज़ी जैसी पढ़ी जाती है।
推导式 是 Python 用一个易读的表达式、从已有可迭代对象构建新集合 — 列表、字典 或 集合 — 的方式。它用一行几乎像英语一样的代码,取代了经典的"建空容器 → 循环 → append"模式。
Read it as a sentence: "n squared, for each n in nums, if n is greater than 3." The brackets decide the container.
इसे वाक्य की तरह पढ़ें: "n का square, nums के हर n के लिए, अगर n 3 से बड़ा है।" Brackets container तय करते हैं।
把它当句子读:"n 的平方,对 nums 中的每个 n,如果 n 大于 3。"括号决定容器类型。
A for loop tells the reader how to build the collection. A comprehension tells the reader what the collection is. That shift from "how" to "what" is the Pythonic mindset. As a bonus, comprehensions are usually a little faster than the equivalent loop — Section 10 shows real measurements.
For loop पढ़ने वाले को बताता है कि collection कैसे बनाना है। Comprehension बताती है कि collection क्या है। "कैसे" से "क्या" की यह बदलाव ही Pythonic सोच है। साथ में, comprehensions आमतौर पर बराबर के loop से थोड़ी तेज़ होती हैं — Section 10 असली माप दिखाता है।
for 循环告诉读者 如何 构建集合;推导式告诉读者集合 是什么。从"如何"到"是什么"的转变,就是 Pythonic 的思维方式。额外的好处是,推导式通常比等价的循环稍快一些 — 第 10 节给出了真实测量结果。
Look for the interactive boxes: the Comprehension Machine (Section 06), the If-Position Lab (07), the Nested Loop Visualizer (08) and Lazy vs Eager with a memory meter (11). Every result they show was produced by real Python.
Interactive डिब्बे खोजें: Comprehension Machine (Section 06), If-Position Lab (07), Nested Loop Visualizer (08) और memory meter के साथ Lazy vs Eager (11)। इनका हर नतीजा असली Python से बना है।
请留意这些互动框:Comprehension Machine(第 06 节)、If-Position Lab(07)、Nested Loop Visualizer(08)以及带内存表的 Lazy vs Eager(11)。它们显示的每个结果都由真实 Python 生成。
The Universal Syntax 🧠सबके लिए एक Syntax 🧠通用语法 🧠
List, dict and set comprehensions share the same skeleton. Learn one shape and you know all three. Only the brackets and the output part change.
List, dict और set comprehensions का ढाँचा एक ही है। एक आकार सीखें और तीनों आ जाते हैं। सिर्फ़ brackets और output वाला हिस्सा बदलता है।
列表、字典和集合推导式共用同一个骨架。学会一种,三种都会了。只有括号和输出部分不同。
List Comprehensions — The Workhorse 🐎List Comprehensions — मेहनती घोड़ा 🐎列表推导式 — 主力军 🐎
List comprehensions are the most common kind. Use one anywhere you would otherwise write a for loop that appends to a list.
List comprehensions सबसे आम हैं। जहाँ भी आप list में append करने वाला for loop लिखते, वहाँ इसे इस्तेमाल करें।
列表推导式最常见。凡是你本来要写一个往列表 append 的 for 循环的地方,都可以用它。
The Loop You Have Always Writtenवह Loop जो आप हमेशा लिखते आए हैं你一直在写的循环
# The old way - 4 lines to square 10 numbers
squares = []
for n in range(10):
squares.append(n ** 2)
print(squares)
The Comprehension That Replaces Itउसकी जगह लेने वाली Comprehension取代它的推导式
# One line. Same result. Clearer intent.
squares = [n ** 2 for n in range(10)]
print(squares)
Adding a FilterFilter जोड़ना加上过滤
# Only even numbers, squared
even_squares = [n ** 2 for n in range(10) if n % 2 == 0]
# Cleaning a list of user inputs
raw = [" Aarav ", "", "Meera", None, " Kabir", " "]
clean = [name.strip() for name in raw if name and name.strip()]
print(even_squares)
print(clean)
Notice the filter if name and name.strip(): name alone drops None and "", and name.strip() also drops " " (only spaces). Without it, an empty string would sneak into the result.
Filter if name and name.strip() पर ध्यान दें: अकेला name, None और "" हटाता है, और name.strip(), " " (सिर्फ़ spaces) भी हटाता है। इसके बिना एक ख़ाली string नतीजे में घुस जाती।
注意过滤条件 if name and name.strip():单独的 name 能去掉 None 和 "",name.strip() 还能去掉 " "(只有空格)。少了它,一个空字符串就会混进结果。
[n**2 for n in range(10) if n % 2 == 0] reads as: "n squared, for each n in range 10, where n is even." If you can read your comprehension out loud like a sentence, it is Pythonic. If you can't, turn it back into a loop.
[n**2 for n in range(10) if n % 2 == 0] ऐसे पढ़ी जाती है: "n का square, range 10 के हर n के लिए, जहाँ n सम है।" अगर आप अपनी comprehension को वाक्य की तरह बोलकर पढ़ सकें, तो वह Pythonic है। न पढ़ सकें, तो उसे वापस loop बना दें।
[n**2 for n in range(10) if n % 2 == 0] 读作:"n 的平方,对 range 10 中的每个 n,当 n 为偶数时。"如果能像句子一样把推导式读出来,它就是 Pythonic 的。读不出来,就改回循环。
Dict Comprehensions — Building Mappings 🔑Dict Comprehensions — Mappings बनाना 🔑字典推导式 — 构建映射 🔑
Dict comprehensions are perfect for transforming, inverting or filtering key-value data. The shape is the same as a list comprehension, but the output is a key: value pair.
Dict comprehensions key-value data को बदलने, उलटने या filter करने के लिए बढ़िया हैं। आकार list comprehension जैसा ही है, पर output एक key: value जोड़ी है।
字典推导式非常适合转换、反转或过滤键值数据。形状与列表推导式相同,只是输出是一个 key: value 对。
Building a Lookup TableLookup Table बनाना构建查找表
# Number -> its square (classic use case)
square_map = {n: n ** 2 for n in range(6)}
print(square_map)
Inverting a Dict (Keys ↔ Values)Dict उलटना (Keys ↔ Values)反转字典(键 ↔ 值)
country_capital = {"India": "New Delhi", "France": "Paris", "Japan": "Tokyo"}
# Flip it - capitals become keys
capital_country = {v: k for k, v in country_capital.items()}
print(capital_country)
# Careful: if two keys share a value, the LAST one wins
team = {"Aarav": "red", "Meera": "blue", "Kabir": "red"}
by_colour = {colour: name for name, colour in team.items()}
print(by_colour) # Aarav was silently overwritten
Dict keys must be unique. When two items produce the same key, the last one silently wins — no error, no warning. Above, "Aarav" vanished. If values can repeat, collect lists instead (see the grouping example in Section 09).
Dict keys अनोखी होनी चाहिए। जब दो items एक ही key बनाएँ, तो आख़िरी वाली चुपचाप जीत जाती है — न error, न चेतावनी। ऊपर "Aarav" ग़ायब हो गया। अगर values दोहरा सकती हैं, तो lists जमा करें (Section 09 का grouping उदाहरण देखें)।
字典的键必须唯一。当两个元素产生同一个键时,最后一个会悄悄胜出 — 不报错,不警告。上面的 "Aarav" 就消失了。如果值可能重复,请改为收集列表(见第 09 节的分组示例)。
Filtering a Dict by ValueValue से Dict Filter करना按值过滤字典
prices = {"apple": 120, "bread": 45, "milk": 60, "paneer": 420}
# Keep items under Rs 100
affordable = {item: price for item, price in prices.items() if price < 100}
print(affordable)
Building a Dict from Two Listsदो Lists से Dict बनाना用两个列表构建字典
names = ["Aarav", "Meera", "Kabir"]
scores = [85, 92, 78]
# zip() pairs them; the comprehension builds the dict
report = {name: score for name, score in zip(names, scores)}
print(report)
# For a plain pairing, dict(zip(...)) does the same job
print(dict(zip(names, scores)))
A dict comprehension has exactly one colon in its output part — between key and value. Everything else is the same as a list comprehension. Forget the colon and you get a set comprehension (or a SyntaxError, as Section 07 shows).
Dict comprehension के output हिस्से में ठीक एक colon होता है — key और value के बीच। बाक़ी सब list comprehension जैसा है। Colon भूलें तो आपको set comprehension मिलती है (या SyntaxError, जैसा Section 07 दिखाता है)।
字典推导式的输出部分 恰好有一个冒号 — 位于键和值之间。其余部分与列表推导式相同。忘了冒号,你得到的就是集合推导式(或 SyntaxError,见第 07 节)。
Set Comprehensions — Instant Deduplication 🎯Set Comprehensions — तुरंत Duplicates हटाना 🎯集合推导式 — 瞬间去重 🎯
Set comprehensions look like dict comprehensions without the colon. They build a set — a collection of unique items with no fixed order. Perfect whenever you want distinct results.
Set comprehensions बिना colon वाली dict comprehensions जैसी दिखती हैं। ये set बनाती हैं — अनोखे items का collection, बिना तय क्रम के। जब भी अलग-अलग नतीजे चाहिए, बढ़िया।
集合推导式看起来像 没有冒号 的字典推导式。它构建集合 — 元素唯一、没有固定顺序 的集合。需要去重结果时非常合适。
Unique Words from a Sentenceएक वाक्य के अनोखे शब्द句子中的不重复单词
text = "The quick brown fox jumps over the lazy dog the fox is quick"
# Unique words, all lowercase
unique_words = {w.lower() for w in text.split()}
print(unique_words) # order is not fixed!
print(sorted(unique_words)) # sort when you need a stable order
print(f"Distinct word count: {len(unique_words)}")
The order of a printed set of strings can change every time you run the program, because Python randomises string hashing for security. The first line of the output above will likely look different on your machine. When order matters, use sorted(...) like the second line.
Strings वाले set का print क्रम हर बार program चलाने पर बदल सकता है, क्योंकि Python सुरक्षा के लिए string hashing को random बनाता है। ऊपर के output की पहली line आपकी मशीन पर शायद अलग दिखेगी। जब क्रम मायने रखे, तो दूसरी line की तरह sorted(...) इस्तेमाल करें।
打印字符串集合时,顺序 每次运行程序都可能不同,因为 Python 出于安全考虑会随机化字符串哈希。上面输出的第一行在你的电脑上很可能不一样。顺序重要时,像第二行那样用 sorted(...)。
Unique File Extensions in a FolderFolder के अनोखे File Extensions文件夹中不重复的扩展名
files = [
"report.pdf", "data.csv", "summary.pdf",
"chart.png", "raw.csv", "notes.md", "logo.png",
]
# Grab the extension of each file, dedupe automatically
extensions = {f.split(".")[-1] for f in files}
print(sorted(extensions))
| LineLine行 | CodeCode代码 |
|---|---|
| 1 | exts = set() |
| 2 | for f in files: |
| 3 | ext = f.split(".")[-1] |
| 4 | exts.add(ext) |
| 4 lines, one accumulator4 lines, एक accumulator4 行,一个累加器 |
| LineLine行 | CodeCode代码 |
|---|---|
| 1 | exts = {f.split(".")[-1] |
for f in files} | |
| 1 expression, no setup1 expression, कोई तैयारी नहीं1 个表达式,无需准备 |
f.split(".")[-1] gives "Makefile" for a file with no dot, and only "gz" for "backup.tar.gz". For real file names, use pathlib: Path(f).suffix is "" for "Makefile", and Path(f).suffixes gives [".tar", ".gz"].
f.split(".")[-1] बिना dot वाली file के लिए "Makefile" देता है, और "backup.tar.gz" के लिए सिर्फ़ "gz"। असली file names के लिए pathlib इस्तेमाल करें: "Makefile" के लिए Path(f).suffix "" है, और Path(f).suffixes [".tar", ".gz"] देता है।
对没有点号的文件,f.split(".")[-1] 会得到 "Makefile";对 "backup.tar.gz" 只得到 "gz"。处理真实文件名请用 pathlib:"Makefile" 的 Path(f).suffix 是 "",而 Path(f).suffixes 给出 [".tar", ".gz"]。
How a Comprehension Runs — Step by Step ⚙️Comprehension कैसे चलती है — कदम-दर-कदम ⚙️推导式如何运行 — 一步一步 ⚙️
in — the list, range, or dict.items() — once, before the loop starts.in के बाद वाला iterable — list, range, या dict.items() — loop शुरू होने से पहले एक बार evaluate करता है।in 之后的可迭代对象 — 列表、range 或 dict.items() — 求值一次。for with .append().for और .append() से कम overhead वाला।for 加 .append() 开销更小。if clause exists, the item is tested. If the condition is false, the item is skipped — the output expression never runs for it.if clause है, तो item जाँचा जाता है। Condition false हो तो item छोड़ दिया जाता है — उसके लिए output expression कभी नहीं चलता।if 子句,就检测这个元素。条件为假则跳过 — 输出表达式根本不会为它运行。Try It — Comprehension Machineकरके देखें — Comprehension Machine动手试试 — 推导式机器
Build any comprehension from the parts below, then press Play. Watch each item leave the conveyor, meet the filter, get transformed and land in the container. The equivalent for loop lights up in step. Try dups with a set, and n % 3 with {expr: n}, to see duplicates and overwritten keys.
नीचे के हिस्सों से कोई भी comprehension बनाएँ, फिर चलाएँ दबाएँ। हर item को conveyor छोड़ते, filter से मिलते, बदलते और container में पहुँचते देखें। बराबर का for loop साथ-साथ जलता है। Duplicates और overwrite होती keys देखने के लिए dups के साथ set, और n % 3 के साथ {expr: n} आज़माएँ।
用下面的部件搭出任意推导式,然后点 播放。看每个元素离开传送带、经过过滤、被转换、落入容器。等价的 for 循环会同步高亮。试试 dups 配 set,以及 n % 3 配 {expr: n},观察重复和被覆盖的键。
The loop variable lives only inside the comprehension. After [n * n for n in range(4)], an outer n is untouched — Section 12 proves it. (In Python 2 it used to leak; Python 3 fixed that.)
Loop variable सिर्फ़ comprehension के अंदर रहता है। [n * n for n in range(4)] के बाद बाहर का n अछूता रहता है — Section 12 इसे साबित करता है। (Python 2 में यह बाहर रिसता था; Python 3 ने इसे ठीक किया।)
循环变量只存在于推导式内部。执行 [n * n for n in range(4)] 之后,外部的 n 不受影响 — 第 12 节会证明。(Python 2 中它会泄漏出去;Python 3 修复了这一点。)
Conditionals — Filter vs Transform 🔀Conditionals — Filter बनाम Transform 🔀条件 — 过滤 vs 转换 🔀
An if can appear in two very different places in a comprehension. Mixing them up is the #1 beginner mistake.
Comprehension में if दो बिल्कुल अलग जगहों पर आ सकता है। इन्हें मिला देना शुरुआती लोगों की नंबर 1 ग़लती है।
if 可以出现在推导式中 两个完全不同的位置。把它们搞混是初学者的头号错误。
if at the end)Filter (अंत में if)过滤(if 在末尾)if/else on the left)Transform (बाईं ओर if/else)转换(if/else 在左边)if c2 at the end) runs first; the survivors are then transformed (a if c1 else b). Powerful — read it twice before writing it.if c2) पहले चलता है; बचे हुए फिर बदले जाते हैं (a if c1 else b)। ताक़तवर — लिखने से पहले दो बार पढ़ें।if c2),再转换留下的元素(a if c1 else b)。很强大 — 写之前读两遍。Side-by-Side Comparisonआमने-सामने तुलना并排比较
nums = [1, 2, 3, 4, 5, 6, 7, 8]
# FILTER: only keep even numbers -> shorter output
evens = [n for n in nums if n % 2 == 0]
# TRANSFORM: mark each number as "even" or "odd" -> same length
labels = ["even" if n % 2 == 0 else "odd" for n in nums]
# BOTH: label only numbers greater than 3
mixed = ["even" if n % 2 == 0 else "odd" for n in nums if n > 3]
print(evens)
print(labels)
print(mixed)
Try It — If-Position Labकरके देखें — If-Position Lab动手试试 — if 位置实验室
Pick a filter, a transform and where they go. The tiles show what happens to each of the numbers 1–8: dropped (✗), kept, or changed. The last two buttons are the broken forms — see the real error Python gives.
एक filter, एक transform और उनकी जगह चुनें। Tiles दिखाती हैं कि 1–8 की हर संख्या का क्या होता है: हटाई गई (✗), रखी गई, या बदली गई। आख़िरी दो buttons टूटे हुए रूप हैं — Python का असली error देखें।
选一个过滤、一个转换以及它们的位置。方块显示 1–8 每个数字的结果:被丢弃(✗)、保留或被改变。最后两个按钮是错误写法 — 看看 Python 给出的真实报错。
Here are the three classic mistakes and the exact messages Python gives:
ये तीन मशहूर ग़लतियाँ हैं और Python के ठीक-ठीक संदेश:
下面是三个经典错误,以及 Python 给出的确切信息:
bad = [
"[n if n > 3 for n in nums]", # if/else on the left needs else
"[n for n in nums if n > 3 else 0]", # a filter cannot have else
"{k, v for k, v in pairs}", # missing colon in a dict
]
for src in bad:
try:
compile(src, "demo", "eval")
except SyntaxError as e:
print(f"{src:36} -> SyntaxError: {e.msg}")
An if after the for is a filter — no else allowed. An if … else before the for is a conditional expression — the else is required. Mix them up and Python raises SyntaxError. Get this right and you will never fear comprehensions again.
for के बाद वाला if filter है — else की इजाज़त नहीं। for से पहले वाला if … else conditional expression है — else ज़रूरी है। इन्हें मिलाएँ तो Python SyntaxError देता है। यह सही कर लें तो comprehensions से कभी डर नहीं लगेगा।
for 之后 的 if 是过滤 — 不能有 else。for 之前 的 if … else 是条件表达式 — 必须有 else。搞混了 Python 就会抛出 SyntaxError。掌握这一点,你就再也不会怕推导式了。
Nested Comprehensions — Flattening and Grids 🧮Nested Comprehensions — Flatten करना और Grids 🧮嵌套推导式 — 展平与网格 🧮
A comprehension can have several for clauses. The rule is simple: they run left to right in the same order as nested for loops written top to bottom.
एक comprehension में कई for clauses हो सकते हैं। नियम सरल है: वे बाएँ से दाएँ, उसी क्रम में चलते हैं जैसे ऊपर से नीचे लिखे nested for loops।
一个推导式可以有多个 for 子句。规则很简单:它们 从左到右运行,顺序与从上到下书写的嵌套 for 循环完全相同。
Flattening a Matrix (List of Lists → List)Matrix को Flatten करना (Lists की List → List)展平矩阵(列表的列表 → 列表)
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
]
# Outer loop first, inner loop second - same order as nested for loops
flat = [n for row in matrix for n in row]
print(flat)
[n for row in matrix for n in row][n for row in matrix for n in row] पढ़ना读懂 [n for row in matrix for n in row]Building a Matrix (a Comprehension Inside a Comprehension)Matrix बनाना (Comprehension के अंदर Comprehension)构建矩阵(推导式中的推导式)
# A 3x3 multiplication table - a list of lists
mult_table = [[i * j for j in range(1, 4)] for i in range(1, 4)]
for row in mult_table:
print(row)
# Transpose: turn rows into columns
transposed = [[row[c] for row in mult_table] for c in range(3)]
print(transposed)
Careful — these two look alike but are different. [x for a in A for x in a] has two fors in one comprehension and gives a flat list. [[x for x in a] for a in A] puts a whole comprehension in the output part and gives a list of lists.
सावधान — ये दोनों एक जैसे दिखते हैं पर अलग हैं। [x for a in A for x in a] में एक comprehension में दो for हैं और यह flat list देता है। [[x for x in a] for a in A] output हिस्से में पूरी comprehension रखता है और lists की list देता है।
注意 — 这两种写法看似相同,其实不同。[x for a in A for x in a] 是一个推导式里有两个 for,得到 扁平 列表。[[x for x in a] for a in A] 把整个推导式放在输出部分,得到 列表的列表。
Cartesian Product (All Pairs)Cartesian Product (सारी जोड़ियाँ)笛卡尔积(所有组合)
colours = ["red", "blue"]
sizes = ["S", "M", "L"]
# Every colour x every size = 6 T-shirts
skus = [f"{c}-{s}" for c in colours for s in sizes]
print(skus)
Try It — Nested Loop Visualizerकरके देखें — Nested Loop Visualizer动手试试 — 嵌套循环可视化
Step through four nested comprehensions. The orange chip is the current value of each loop variable. Notice how the inner loop restarts every time the outer loop moves one step.
चार nested comprehensions को कदम-दर-कदम चलाएँ। नारंगी chip हर loop variable की मौजूदा value है। देखें कि बाहरी loop के एक कदम बढ़ते ही अंदरूनी loop फिर से शुरू होता है।
逐步执行四个嵌套推导式。橙色方块是每个循环变量的当前值。注意外层循环每前进一步,内层循环都会从头开始。
Two fors in one comprehension is fine. Three is hard to read. If you reach for triple nesting, stop and split it into a helper function or plain loops. Clever code that nobody can maintain is a liability, not an asset.
एक comprehension में दो for ठीक हैं। तीन पढ़ना मुश्किल है। अगर तिहरी nesting की ओर बढ़ें, तो रुकें और उसे helper function या सामान्य loops में बाँटें। ऐसा चालाक code जिसे कोई maintain न कर सके, बोझ है, संपत्ति नहीं।
一个推导式里两个 for 没问题。三个就难读了。如果你想写三层嵌套,停下来,把它拆成辅助函数或普通循环。没人能维护的"聪明"代码是负债,不是资产。
Practical Real-World Examples 🛠️असली दुनिया के उदाहरण 🛠️实用的真实示例 🛠️
Example 1 — Cleaning Messy CSV Dataउदाहरण 1 — गंदे CSV Data को साफ़ करना示例 1 — 清洗杂乱的 CSV 数据
raw_rows = [
" Aarav, 25 , aarav@example.com ",
"Meera,30,meera@example.com",
" Kabir , 28,kabir@example.com ",
"", # blank row
]
# Split, strip whitespace, skip blanks - all in one pass
clean = [
[field.strip() for field in row.split(",")]
for row in raw_rows if row.strip()
]
for row in clean:
print(row)
For real CSV files, use the built-in csv module — it handles commas inside quotes, which a simple split(",") cannot.
असली CSV files के लिए built-in csv module इस्तेमाल करें — यह quotes के अंदर के commas संभालता है, जो सीधा split(",") नहीं कर सकता।
处理真实 CSV 文件请用内置的 csv 模块 — 它能处理引号内的逗号,而简单的 split(",") 做不到。
Example 2 — Counting Word Frequenciesउदाहरण 2 — शब्दों की गिनती示例 2 — 统计词频
from collections import Counter
text = "the cat sat on the mat the cat is fat"
words = text.split()
# Works, but counts the whole list again for EVERY unique word
freq = {w: words.count(w) for w in words}
print(freq)
# Better: one pass, made for exactly this job
print(Counter(words).most_common(3))
{w: words.count(w) for w in words} looks neat, but count() scans the whole list for every word. With 100,000 words that is billions of steps. collections.Counter counts everything in one pass — use it for real data.
{w: words.count(w) for w in words} सुंदर दिखता है, पर count() हर शब्द के लिए पूरी list scan करता है। 100,000 शब्दों पर यह अरबों कदम हैं। collections.Counter एक ही बार में सब गिनता है — असली data के लिए इसे इस्तेमाल करें।
{w: words.count(w) for w in words} 看起来很简洁,但 count() 会为每个单词扫描整个列表。10 万个单词就是数十亿步。collections.Counter 一次遍历就能数完 — 真实数据请用它。
Example 3 — Grouping Users by Domainउदाहरण 3 — Domain के हिसाब से Users को समूह में रखना示例 3 — 按域名分组用户
emails = ["aarav@gmail.com", "meera@yahoo.com",
"kabir@gmail.com", "dev@outlook.com",
"isha@yahoo.com", "rohan@notgmail.com"]
# Split once into (user, domain) pairs
pairs = [e.split("@") for e in emails]
# Group users under each domain (sorted, so the order is stable)
grouped = {
d: [user for user, dom in pairs if dom == d]
for d in sorted({dom for _, dom in pairs})
}
for domain, users in grouped.items():
print(f"{domain}: {users}")
e.endswith(d)?e.endswith(d) क्यों नहीं?为什么不用 e.endswith(d)?A shorter version checks e.endswith(d). It has a bug: "rohan@notgmail.com".endswith("gmail.com") is True, so Rohan would appear under gmail.com too. Splitting on "@" and comparing the domain exactly avoids this. Sorting the domains also gives a stable order, because a set has none.
एक छोटा version e.endswith(d) जाँचता है। उसमें bug है: "rohan@notgmail.com".endswith("gmail.com") True है, इसलिए Rohan gmail.com के नीचे भी दिखता। "@" पर split करके domain की ठीक-ठीक तुलना से यह बचता है। Domains को sort करने से क्रम भी स्थिर रहता है, क्योंकि set का कोई क्रम नहीं होता।
更短的写法是检查 e.endswith(d)。它有个 bug:"rohan@notgmail.com".endswith("gmail.com") 为 True,Rohan 也会出现在 gmail.com 下。按 "@" 拆分并精确比较域名可以避免这个问题。对域名排序还能得到稳定顺序,因为集合本身没有顺序。
Example 4 — A Small Data Pipelineउदाहरण 4 — एक छोटी Data Pipeline示例 4 — 一个小型数据管道
transactions = [
{"id": 1, "amount": 100, "status": "paid"},
{"id": 2, "amount": 250, "status": "pending"},
{"id": 3, "amount": 75, "status": "paid"},
{"id": 4, "amount": 500, "status": "paid"},
]
# IDs of paid transactions over Rs 100
big_paid = [t["id"] for t in transactions
if t["status"] == "paid" and t["amount"] > 100]
# Total amount by status
statuses = sorted({t["status"] for t in transactions})
total_by_status = {
s: sum(t["amount"] for t in transactions if t["status"] == s)
for s in statuses
}
print("Big paid IDs:", big_paid)
print("Totals: ", total_by_status)
Note the generator expression inside sum(...) — no extra brackets needed. Section 11 explains why it uses less memory.
sum(...) के अंदर generator expression पर ध्यान दें — अतिरिक्त brackets की ज़रूरत नहीं। Section 11 बताता है कि यह कम memory क्यों लेता है।
注意 sum(...) 里的生成器表达式 — 不需要额外括号。第 11 节解释它为什么更省内存。
Performance — Are Comprehensions Actually Faster? ⚡Performance — क्या Comprehensions सच में तेज़ हैं? ⚡性能 — 推导式真的更快吗?⚡
Usually, yes — but by less than people claim. Here is a real measurement: squaring 100,000 numbers, 100 times, four ways.
आमतौर पर हाँ — पर लोग जितना कहते हैं उससे कम। यह असली माप है: 100,000 संख्याओं का square, 100 बार, चार तरीकों से।
通常是的 — 但没有人们说的那么夸张。下面是真实测量:对 100,000 个数求平方,重复 100 次,四种写法。
import timeit
# Squaring 100,000 numbers - four different ways, 100 runs each
setup = "nums = range(100_000)"
tests = {
"for loop + append": "result = []\nfor n in nums: result.append(n * n)",
"list comprehension": "result = [n * n for n in nums]",
"map + lambda": "result = list(map(lambda n: n * n, nums))",
"generator into list": "result = list(n * n for n in nums)",
}
for name, stmt in tests.items():
t = timeit.timeit(stmt, setup=setup, number=100)
print(f"{name:20} {t:.3f}s")
The list comprehension was the fastest here — about 1.4× faster than the loop with .append(). Your numbers will differ, but the ranking is usually the same.
यहाँ list comprehension सबसे तेज़ रही — .append() वाले loop से लगभग 1.4× तेज़। आपके numbers अलग होंगे, पर क्रम आमतौर पर वही रहता है।
这里列表推导式最快 — 约为带 .append() 的循环的 1.4 倍。你的数字会不同,但排名通常一致。
| Approachतरीका写法 | Speedगति速度 | Readabilityपढ़ने में可读性 | When to useकब इस्तेमाल करें何时使用 |
|---|---|---|---|
| ComprehensionComprehension推导式 | Fastest hereयहाँ सबसे तेज़这里最快 | Excellent for simple expressionsसरल expressions के लिए बेहतरीन简单表达式时极佳 | The default for building a collectionCollection बनाने का default构建集合时的默认选择 |
| For loop + appendFor loop + appendfor 循环 + append | A bit slowerथोड़ा धीमा稍慢 | Best for multi-step logicकई कदमों वाले logic के लिए सबसे अच्छा多步骤逻辑最佳 | Side effects, try/except, break, many stepsSide effects, try/except, break, कई कदम副作用、try/except、break、多步骤 |
| map() + lambda | Slower (a function call per item)धीमा (हर item पर function call)较慢(每个元素一次函数调用) | Less readableकम पठनीय可读性较差 | With a ready-made function: map(str, nums) is fineतैयार function के साथ: map(str, nums) ठीक है配合现成函数:map(str, nums) 没问题 |
list( generator )list( generator )list(生成器) | Slower than [...][...] से धीमा比 [...] 慢 | Fineठीक尚可 | Just write [...] insteadइसकी जगह सीधे [...] लिखें直接写 [...] 即可 |
A loop with result.append(x) must look up the append method and call it on every turn. A list comprehension uses a special bytecode instruction (LIST_APPEND) instead, so there is no method lookup and no call. Since Python 3.12 (PEP 709), comprehensions are also inlined into the surrounding function, which removes the cost of creating a hidden function. The loop itself still runs in Python — it is just leaner.
result.append(x) वाले loop को हर चक्कर में append method ढूँढना और बुलाना पड़ता है। List comprehension इसकी जगह एक ख़ास bytecode instruction (LIST_APPEND) इस्तेमाल करती है, इसलिए न method lookup, न call। Python 3.12 (PEP 709) से comprehensions आसपास के function में inline भी होती हैं, जिससे एक छिपा function बनाने का ख़र्च हट जाता है। Loop फिर भी Python में ही चलता है — बस हल्का है।
带 result.append(x) 的循环每一轮都要查找并调用 append 方法。列表推导式改用专门的字节码指令(LIST_APPEND),没有方法查找也没有调用。从 Python 3.12(PEP 709)起,推导式还会被 内联 到所在函数中,省去了创建隐藏函数的开销。循环本身仍在 Python 中运行 — 只是更精简。
Generator Expressions — The Lazy Cousin 🌱Generator Expressions — आलसी चचेरा भाई 🌱生成器表达式 — 懒惰的表亲 🌱
Swap the square brackets for round brackets and you get a generator expression. It looks like a list comprehension, but it produces values one at a time, only when asked — so it uses almost no memory, even for millions of items.
Square brackets की जगह गोल brackets लगाएँ और आपको generator expression मिलता है। यह list comprehension जैसा दिखता है, पर values एक-एक करके, सिर्फ़ माँगने पर बनाता है — इसलिए लाखों items के लिए भी लगभग कोई memory नहीं लेता।
把方括号换成 圆括号,就得到 生成器表达式。它看起来像列表推导式,但 一次只产生一个值,而且只在被请求时才产生 — 所以即使有几百万个元素,也几乎不占内存。
import sys, tracemalloc
N = 10_000_000
tracemalloc.start()
squares_list = [n ** 2 for n in range(N)] # builds ALL values now
list_mb = tracemalloc.get_traced_memory()[0] / 1_000_000
del squares_list
tracemalloc.stop()
squares_gen = (n ** 2 for n in range(N)) # builds nothing yet
print(f"list comprehension: {list_mb:,.0f} MB")
print(f"generator expression: {sys.getsizeof(squares_gen)} bytes")
# Both work with sum() - but only the generator is memory-safe
total = sum(n ** 2 for n in range(N))
print(f"Sum of squares 0-9,999,999: {total:,}")
These numbers are real. The list needed about 409 MB; the generator object is 200 bytes and stays that size no matter how big N is. Both give the same sum.
ये numbers असली हैं। List को लगभग 409 MB चाहिए थे; generator object 200 bytes का है और N कितना भी बड़ा हो, उतना ही रहता है। दोनों एक ही जोड़ देते हैं।
这些数字是真实的。列表需要约 409 MB;生成器对象只有 200 字节,无论 N 多大都保持不变。两者求和结果相同。
Lazy Means "Not Until You Ask"आलसी मतलब "जब तक माँगो नहीं"懒惰就是"你不要就不算"
def square(n):
print(f" computing {n}")
return n * n
print("list comprehension:")
lst = [square(n) for n in range(3)] # all work happens NOW
print("built:", lst)
print("generator expression:")
gen = (square(n) for n in range(3)) # nothing computed yet
print("created")
print("next ->", next(gen))
print("next ->", next(gen))
print("rest ->", list(gen))
print("again ->", list(gen)) # exhausted: one-shot only
Try It — Lazy vs Eagerकरके देखें — Lazy बनाम Eager动手试试 — 惰性 vs 急切
Left: a list comprehension does all the work at once. Right: a generator does nothing until you call next(). Click the buttons and watch when computing … appears. Below, the memory meter shows measured sizes.
बाएँ: list comprehension सारा काम एक साथ करती है। दाएँ: generator तब तक कुछ नहीं करता जब तक आप next() न बुलाएँ। Buttons दबाएँ और देखें computing … कब आता है। नीचे memory meter नापे गए sizes दिखाता है।
左边:列表推导式一次做完所有工作。右边:生成器在你调用 next() 之前什么都不做。点按钮,看 computing … 何时出现。下方的内存表显示实测大小。
| Traitगुण特性 | Behaviourव्यवहार表现 |
|---|---|
| BracketsBrackets括号 | [ ] |
| MemoryMemory内存 | Stores every itemहर item रखती है存储所有元素 |
| Reusableदोबारा इस्तेमाल可重复使用 | Yes — loop over it many timesहाँ — कई बार loop करें是 — 可多次遍历 |
| Extrasऔर其他 | len(), indexing, slicinglen(), indexing, slicinglen()、索引、切片 |
| Best forकिसके लिए适合 | Small/medium data you use more than onceछोटा/मध्यम data जो एक से ज़्यादा बार इस्तेमाल हो多次使用的中小数据 |
| Traitगुण特性 | Behaviourव्यवहार表现 |
|---|---|
| BracketsBrackets括号 | ( ) |
| MemoryMemory内存 | One item at a timeएक बार में एक item一次一个元素 |
| Reusableदोबारा इस्तेमाल可重复使用 | No — one pass onlyनहीं — सिर्फ़ एक बार否 — 只能遍历一次 |
| Extrasऔर其他 | No len(), no indexinglen() नहीं, indexing नहीं没有 len(),不能索引 |
| Best forकिसके लिए适合 | Huge data, streams, a single sum/max/anyबहुत बड़ा data, streams, एक बार का sum/max/any超大数据、流、一次性的 sum/max/any |
When a generator expression is the only argument to a function, you can drop its own brackets: sum(n ** 2 for n in range(1000)) is clean; sum((n ** 2 for n in range(1000))) is legal but noisy. With a second argument, the brackets are required: sorted((n % 7 for n in nums), reverse=True).
जब generator expression किसी function का इकलौता argument हो, तो उसके अपने brackets हटा सकते हैं: sum(n ** 2 for n in range(1000)) साफ़ है; sum((n ** 2 for n in range(1000))) सही है पर भारी। दूसरे argument के साथ brackets ज़रूरी हैं: sorted((n % 7 for n in nums), reverse=True)।
当生成器表达式是函数的 唯一 参数时,可以省去它自己的括号:sum(n ** 2 for n in range(1000)) 很简洁;sum((n ** 2 for n in range(1000))) 合法但累赘。有第二个参数时必须加括号:sorted((n % 7 for n in nums), reverse=True)。
Scope — What Stays Inside, and the Walrus Exception 🔒Scope — क्या अंदर रहता है, और Walrus का अपवाद 🔒作用域 — 什么留在里面,以及海象运算符的例外 🔒
The loop variable of a comprehension belongs to the comprehension. It does not overwrite a variable with the same name outside. There is one deliberate exception: a name assigned with the walrus operator := (Python 3.8+) is stored in the surrounding scope.
Comprehension का loop variable comprehension का ही होता है। यह बाहर के उसी नाम वाले variable को overwrite नहीं करता। एक जान-बूझकर अपवाद है: walrus operator := (Python 3.8+) से दिया गया नाम आसपास के scope में रखा जाता है।
推导式的循环变量属于推导式本身,不会覆盖外部同名变量。有一个有意设计的例外:用海象运算符 :=(Python 3.8+)赋值的名字会保存在外层作用域中。
n = "outer"
squares = [n * n for n in range(4)]
print(n) # the loop variable did not leak
# The walrus operator := is the one exception: it DOES leak
data = [3, 8, 12, 5]
big = [y for x in data if (y := x * 10) > 50]
print(big, y) # y is visible outside
The walrus here computes x * 10 once and uses it twice — in the filter and in the output. Handy, but use it sparingly; it makes a comprehension harder to read.
यहाँ walrus x * 10 एक बार गिनकर दो बार इस्तेमाल करता है — filter में और output में। काम का है, पर कम इस्तेमाल करें; इससे comprehension पढ़ना मुश्किल होता है।
这里海象运算符只计算一次 x * 10,却用了两次 — 在过滤条件和输出中。很方便,但要少用;它会让推导式更难读。
When NOT to Use a Comprehension 🚫Comprehension कब इस्तेमाल न करें 🚫什么时候不该用推导式 🚫
Comprehensions are powerful, but they do not replace every loop. Use a plain for loop when the logic no longer fits comfortably in one expression.
Comprehensions ताक़तवर हैं, पर हर loop की जगह नहीं लेतीं। जब logic एक expression में आराम से न समाए, तो सामान्य for loop इस्तेमाल करें।
推导式很强大,但不能取代所有循环。当逻辑无法舒适地放进一个表达式时,就用普通 for 循环。
try/except, several statements or break inside a comprehension. When you need any of them, a loop is not just cleaner — it is the only option.try/except, कई statements या break नहीं रख सकते। जब इनमें से कुछ भी चाहिए, तो loop सिर्फ़ साफ़ नहीं — इकलौता रास्ता है।try/except、多条语句或 break。需要其中任何一个时,循环不只是更清晰 — 而是唯一的选择。Bad Idea — A Comprehension for Side Effectsबुरा विचार — Side Effects के लिए Comprehension坏主意 — 为副作用写推导式
users = ["aarav", "meera", "kabir"]
# DON'T DO THIS - building a throwaway list just to run print()
result = [print(user) for user in users]
print(result) # a list of None values, nobody needs it
# DO THIS instead
for user in users:
print(user.title())
A good comprehension fits on one line, or breaks naturally across 2–3 short lines. If yours wraps past that, or the reader has to count brackets to understand it, refactor. The whole point was clarity — lose that and you have lost the win.
अच्छी comprehension एक line में आती है, या स्वाभाविक रूप से 2–3 छोटी lines में बँटती है। अगर आपकी उससे आगे जाए, या पढ़ने वाले को समझने के लिए brackets गिनने पड़ें, तो refactor करें। मक़सद साफ़ता थी — वह खोई तो जीत भी गई।
好的推导式能写在一行内,或自然地拆成 2–3 个短行。如果超出这个长度,或者读者得数括号才能看懂,就重构。初衷就是清晰 — 失去了清晰,也就失去了优势。
Comparison Table — All Four at a Glance 📋तुलना Table — चारों एक नज़र में 📋对比表 — 四种一览 📋
| Featureविशेषता特性 | List | Dict | Set | Generator |
|---|---|---|---|---|
| SyntaxSyntax语法 | [expr for x in it] | {k: v for x in it} | {expr for x in it} | (expr for x in it) |
| Returnsलौटाता है返回 | list | dict | set | generator |
| Orderक्रम顺序 | Keptबना रहता है保持 | Insertion order (3.7+)डालने का क्रम (3.7+)插入顺序(3.7+) | No fixed orderकोई तय क्रम नहीं无固定顺序 | Same as the sourceSource जैसा与源相同 |
| DuplicatesDuplicates重复 | Allowedइजाज़त है允许 | Keys unique (last wins)Keys अनोखी (आख़िरी जीतती है)键唯一(后者胜出) | Removedहटा दिए जाते हैं自动去除 | Allowedइजाज़त है允许 |
| Element ruleElement का नियम元素要求 | Anythingकुछ भी任意 | Keys must be hashableKeys hashable हों键必须可哈希 | Must be hashableHashable हों必须可哈希 | Anythingकुछ भी任意 |
| MemoryMemory内存 | All itemsसारे items全部元素 | All pairsसारी जोड़ियाँ全部键值对 | All unique itemsसारे अनोखे items全部唯一元素 | One at a timeएक बार में एक一次一个 |
| Best forकिसके लिए适合 | General lists, transformsआम lists, बदलाव通用列表、转换 | Lookups, mappings, invertingLookups, mappings, उलटना查找表、映射、反转 | Deduplication, membership testsDuplicates हटाना, membership जाँच去重、成员检测 | Big data, one passबड़ा data, एक बार大数据、单次遍历 |
Golden Rules and Quick Quiz 🏆सुनहरे नियम और छोटा Quiz 🏆黄金法则与小测验 🏆
if goes at the end; an if … else transform goes at the front. The filter drops items; the transform changes them.if अंत में; if … else transform आगे। Filter items हटाता है; transform उन्हें बदलता है।if 放末尾;if … else 转换放前面。过滤丢弃元素,转换改变元素。print, file writes or API calls. If you don't keep the result, use a loop.print, न file writes, न API calls। अगर नतीजा नहीं रखते, तो loop इस्तेमाल करें।print、写文件或调 API。如果不保留结果,就用循环。fors is the ceiling. The first for is the outer loop. Beyond two levels, use a helper function or plain loops.for ही छत है। पहला for बाहरी loop है। दो स्तरों से आगे helper function या सामान्य loops इस्तेमाल करें।for 是上限。第一个 for 是外层循环。超过两层就用辅助函数或普通循环。sum(), max(), any(). Remember: it can be used only once.sum(), max(), any() के साथ बढ़िया चलता है। याद रखें: इसे सिर्फ़ एक बार इस्तेमाल कर सकते हैं।sum()、max()、any() 完美配合。记住:它只能用一次。{k, v for …} and you get a SyntaxError.{k, v for …} लिखें तो SyntaxError।{k, v for …} 则得到 SyntaxError。sorted() when you need a stable order.sorted() इस्तेमाल करें।sorted()。:= does.:= से दिया गया नाम रिसता है।:= 赋值的名字会。Quick Quiz — 8 Questionsछोटा Quiz — 8 सवाल小测验 — 8 道题
A comprehension is a for loop turned into a description: output, for, optional if, wrapped in the brackets of the container you want. Put filters at the end and transforms at the front, keep it to two fors, switch to round brackets for big data, and fall back to a plain loop whenever clarity suffers.
Comprehension एक for loop है जिसे वर्णन में बदला गया: output, for, वैकल्पिक if, और चाहे गए container के brackets। Filters अंत में और transforms आगे रखें, दो for तक सीमित रहें, बड़े data के लिए गोल brackets लें, और जब भी साफ़ता घटे, सामान्य loop पर लौट आएँ।
推导式就是把 for 循环变成一句描述:输出、for、可选的 if,再套上你想要的容器的括号。过滤放末尾,转换放前面,最多两个 for,大数据换成圆括号;一旦清晰度受损,就回到普通循环。