लिस्ट्स, डिक्शनरीज़, सेट्स, लूप्स और कॉम्प्रिहेंशन्स
पायथन के चारों कंटेनरों का सही उपयोग, लूप्स और शर्तें, कॉम्प्रिहेंशन्स, और अव्यवस्थित टिकट्स में से सटीक व पुनरुत्पादनीय टॉप 5 शब्द निकालना।
आप कैसे सीखना चाहते हैं?
वह समस्या जिसे हम हल कर रहे हैं
सपोर्ट प्रमुख यह जानना चाहते हैं कि इस हफ़्ते के टिकट्स में ग्राहकों ने सबसे ज़्यादा किस बात की शिकायत की है। टिकट्स अव्यवस्थित (messy) टेक्स्ट हैं — कुछ बड़े अक्षरों में (capitals), कुछ विराम चिह्नों से भरे, कुछ एक ही बात दो बार दोहराने वाले। एक सहकर्मी ने पाँच मिनट में एक स्क्रिप्ट लिखी और एक सूची भेजी: सबसे ऊपर the, फिर refund, फिर Refund और refund. अलग-अलग प्रविष्टियों (entries) के रूप में।
दूसरे रन में एक और समस्या आई: टिकट्स के क्रम में ज़रा सा बदलाव करने पर टॉप पाँच का पाँचवाँ शब्द बदल गया, जबकि किसी भी शब्द की गिनती नहीं बदली थी। रिपोर्ट पढ़ने वाला कोई भी व्यक्ति यह नहीं बता सका कि कौन सा वर्ज़न सही था।
इसका समाधान कोई विशेष लाइब्रेरी नहीं है। यह पायथन के चार बुनियादी कंटेनर्स हैं — lists, tuples, dictionaries और sets — और सही ढंग से उपयोग किए गए लूप्स व शर्तें। एक एआई इंजीनियर के दैनिक कार्य का एक बड़ा हिस्सा ठीक यही होता है: टेक्स्ट को साफ़ करना, गिनना, फ़िल्टर करना और सॉर्ट करना, इस तरह से कि समान इनपुट के लिए हर बार बिल्कुल वही परिणाम मिले।
इस अध्याय के अंत में आप कर पाएंगे
- किसी कार्य के लिए list, tuple, dictionary और set के बीच चयन करना, और उसका कारण बताना
for,while,if/elif/else,enumerateऔर.items()के साथ स्पष्ट व स्वच्छ लूप्स लिखना- list, dictionary और set कॉम्प्रिहेंशन्स के साथ डेटा को फ़िल्टर और रूपांतरित करना
- अव्यवस्थित टेक्स्ट से शब्दों को निकालना और उन्हें डिक्शनरी व
Counterसे गिनना - समान गिनती वाले शब्दों को एक स्पष्ट नियम के अनुसार सॉर्ट करना, ताकि परिणाम हर बार एक समान आए
ज़रूरी शर्तें: pathlib, JSON/YAML कॉन्फ़िगरेशन और एनवायरनमेंट वेरिएबल्स — और uv run के साथ एक स्क्रिप्ट चला पाना।
चार कंटेनर्स, चार अलग-अलग काम
सबसे पहले, चारों कंटेनर्स आमने-सामने:
tickets = ["refund", "login", "refund", "billing"]
latest = ("T-1042", "refund", 3)
owners = {"refund": "Maya", "login": "Omar"}
seen = set(tickets)
print(tickets[0], tickets[-1], len(tickets))
print(latest[1])
print(owners["login"])
print(sorted(seen))
print("login" in seen, "shipping" in seen)refund billing 4
refund
Omar
['billing', 'login', 'refund']
True Falseप्रत्येक कंटेनर एक अलग वादा करता है, और आप अपनी आवश्यकता के वादे के अनुसार चयन करते हैं:
- List (
[...]) — क्रम बनाए रखती है, एक ही मान को एक से अधिक बार रखने की अनुमति देती है, बदली जा सकती है (mutable)। "एक के बाद एक आने वाली चीज़ों की कतार" के लिए: टिकट्स की सूची, प्रॉम्प्ट्स का बैच। - Tuple (
(...)) — क्रम बनाए रखता है लेकिन बनने के बाद बदला नहीं जा सकता (immutable)। कुछ मानों के समूह के लिए जो मिलकर एक रिकॉर्ड बनाते हैं, जैसे("T-1042", "refund", 3)— id, श्रेणी, प्राथमिकता। यहाँ स्थिति (position) का अपना अर्थ होता है। - Dictionary (
{key: value}) — key द्वारा मान खोजना। "किस श्रेणी का मालिक कौन है", "प्रत्येक शब्द कितनी बार आया" — जहाँ भी आप एक चीज़ से दूसरी चीज़ पर पहुँचते हैं। - Set (
set(...)या{a, b}) — प्रत्येक मान केवल एक बार, कोई निश्चित क्रम नहीं। जब केवल यह सवाल हो कि "क्या यह मौजूद है" या "कितने विशिष्ट (unique) मान हैं"।
sorted(seen) इसलिए प्रिंट किया गया है क्योंकि किसी सेट के प्रिंट होने के क्रम की कोई गारंटी नहीं होती — यह एक रन में एक तरह दिख सकता है और अगले में दूसरी तरह। यदि किसी प्रोग्राम का आउटपुट सेट के क्रम पर निर्भर करता है, तो वह आउटपुट भी स्थिर नहीं रहेगा।
किसी लिस्ट परinएक-एक करके प्रत्येक तत्व की जाँच करता है; जबकि किसी सेट या डिक्शनरी पर यह तुरंत उत्तर देता है, चाहे दस तत्व हों या दस लाख। यदि आप बार-बारif word in stop_wordsकी जाँच करते हैं, तोstop_wordsको एक सेट होना चाहिए, लिस्ट नहीं। ऐसा क्यों है और इस अंतर को कैसे मापें, यह कोर्स में आगे विस्तार से आएगा।
लूप्स: स्पष्ट कहें कि आप किस चीज़ पर लूप चला रहे हैं
टुपल्स और डिक्शनरीज़ पर लूप अनपॅकिंग (unpacking) के साथ सबसे स्पष्ट पढ़े जाते हैं — मान सीधे नामित वेरिएबल्स में जाते हैं:
ticket_id, category, priority = ("T-1042", "refund", 3)
print(ticket_id, category, priority)
owners = {"refund": "Maya", "login": "Omar"}
for category, owner in owners.items():
print(f"{category} -> {owner}")
for position, category in enumerate(["refund", "login"], start=1):
print(position, category)T-1042 refund 3
refund -> Maya
login -> Omar
1 refund
2 login.items() हर बार एक (key, value) युग्म देता है, और enumerate प्रत्येक तत्व को उसकी स्थिति के साथ देता है — range(len(...)) के साथ इंडेक्स गिनने की कोई आवश्यकता नहीं होती। पायथन 3.7 से डिक्शनरी उस क्रम को याद रखती है जिसमें उसकी keys डाली गई थीं, इसलिए owners पर लूप refund से शुरू होता है।
यदि आप .items() लगाना भूल जाएँ तो क्या होगा?
owners = {"refund": "Maya", "login": "Omar"}
for category, owner in owners:
print(category, owner)Traceback (most recent call last):
File "main.py", line 2, in <module>
for category, owner in owners:
^^^^^^^^^^^^^^^
ValueError: too many values to unpack (expected 2)डिक्शनरी पर सीधे लूप चलाने से केवल keys मिलती हैं। पहली key, "refund", छह वर्णों की एक स्ट्रिंग है, और पायथन उसे दो वेरिएबल्स में बाँटने की कोशिश करता है — छह वर्ण, दो स्लॉट। यह संदेश तब तक अजीब लगता है जब तक आप यह याद न करें कि स्ट्रिंग भी एक अनुक्रम (sequence) है।
if/elif/else पहली ऐसी शर्त पर रुक जाता है जो सत्य होती है, इसलिए शर्तों का क्रम ही लॉजिक होता है:
latencies_ms = [120, 340, 95, 1800, 210, 2600]
for latency in latencies_ms:
if latency >= 2000:
label = "critical"
elif latency >= 1000:
label = "slow"
else:
label = "ok"
print(latency, label)120 ok
340 ok
95 ok
1800 slow
210 ok
2600 criticalयदि आप शर्तों को उल्टे क्रम में लिख दें —>= 1000पहले,>= 2000बाद में — तो कोई एरर नहीं आएगा, लेकिन2600का लेबलslowबन जाएगा, क्योंकि पहली शर्त सत्य हो जाती है और श्रृंखला वहीं रुक जाती है।criticalवाली शाखा फिर कभी नहीं चलेगी। जब आप थ्रेशोल्ड्स (सीमाओं) के आधार पर विभाजन करें, तो सबसे सख्त शर्त को हमेशा पहले रखें।
for एक ज्ञात कलेक्शन पर चलता है। while तब तक चलता है जब तक कोई शर्त बनी रहती है — जब आपको पहले से पता नहीं होता कि इसमें कितने चरण लगेंगे। किसी API से पृष्ठ-दर-पृष्ठ (page by page) डेटा प्राप्त करना इसका उत्कृष्ट उदाहरण है। यहाँ एक डिक्शनरी API की भूमिका निभाती है:
pages = {1: ["t1", "t2"], 2: ["t3"], 3: []}
page = 1
collected = []
while True:
batch = pages[page]
if not batch:
break
collected.extend(batch)
page += 1
print(collected, "pages read:", page - 1)['t1', 't2', 't3'] pages read: 2खाली पृष्ठ मिलने का अर्थ है break। if not batch इसलिए काम करता है क्योंकि खाली लिस्ट असत्य (falsy) होती है। ऐसे लूप्स में रुकने की शर्त को हमेशा पहले लिखें और बाकी काम बाद में — एक while True जो रुकना भूल जाए, वह बिना किसी एरर के अनंत काल तक चलता रहता है।
कॉम्प्रिहेंशन्स: एक कलेक्शन से दूसरा कलेक्शन बनाना
"एक खाली लिस्ट, एक लूप, एक if, एक append" — यह चार-पंक्तियों वाला पैटर्न इतना आम है कि पायथन में इसके लिए एक-पंक्ति का प्रारूप है:
latencies_ms = [120, 340, 95, 1800, 210, 2600]
slow = [ms for ms in latencies_ms if ms >= 1000]
seconds = [ms / 1000 for ms in latencies_ms]
labels = {ms: ("slow" if ms >= 1000 else "ok") for ms in latencies_ms}
buckets = {ms // 1000 for ms in latencies_ms}
print(slow)
print(seconds)
print(labels)
print(sorted(buckets))[1800, 2600]
[0.12, 0.34, 0.095, 1.8, 0.21, 2.6]
{120: 'ok', 340: 'ok', 95: 'ok', 1800: 'slow', 210: 'ok', 2600: 'slow'}
[0, 1, 2]इसे पढ़ने का तरीका: [result for element in collection if condition]। बायाँ भाग बताता है कि प्रत्येक तत्व से क्या बनाना है; अंत का if बताता है कि किन्हें रखना है। {key: value for ...} वाला यही आकार एक डिक्शनरी बनाता है, और {value for ...} एक सेट — buckets में तीन अलग-अलग एक-सेकंड वाले बकेट हैं, प्रत्येक एक बार।
दोनों तरह के if में भ्रमित न हों। अंत में आने वाला if ms >= 1000 एक फ़िल्टर (filter) है — जब यह असत्य होता है, तो तत्व को छोड़ दिया जाता है। "slow" if ms >= 1000 else "ok" एक विकल्प (choice/ternary) है — प्रत्येक तत्व बना रहता है, और उसका मान दोनों में से एक होता है। इसीलिए labels में सभी छह तत्व मौजूद हैं।
कॉम्प्रिहेंशन का उद्देश्य एक नया कलेक्शन बनाना है। जब आप केवल कुछ प्रिंट करना चाहते हैं या किसी फ़ाइल में लिखना चाहते हैं — जहाँ परिणाम फेंक दिया जाएगा — तो एक साधारण for लूप लिखें। और तीन स्तरों का नेस्टेड कॉम्प्रिहेंशन भले ही एक लाइन में आ जाए, लेकिन सहकर्मी के पढ़ने के लिए पाँच लाइनों का लूप अक्सर बहुत आसान होता है।
शब्द गिनना: पहले हाथ से, फिर Counter के साथ
डिक्शनरी से गिनने का लगभग हर किसी का पहला प्रयास ऐसा दिखता है:
words = ["refund", "late", "refund", "login", "refund", "late"]
counts = {}
for word in words:
counts[word] += 1Traceback (most recent call last):
File "main.py", line 5, in <module>
counts[word] += 1
~~~~~~^^^^^^
KeyError: 'refund'counts[word] += 1 का अर्थ है counts[word] = counts[word] + 1 — और दाईं ओर counts[word] पढ़ने पर पता चलता है कि key "refund" अभी मौजूद ही नहीं है। पहली बार देखे गए शब्द को एक प्रारंभिक मान की आवश्यकता होती है। .get(key, 0) ठीक यही सुविधा प्रदान करता है:
words = ["refund", "late", "refund", "login", "refund", "late"]
counts = {}
for word in words:
counts[word] = counts.get(word, 0) + 1
print(counts){'refund': 3, 'late': 2, 'login': 1}यह कार्य इतना आम है कि स्टैंडर्ड लाइब्रेरी में इसके लिए एक समर्पित प्रकार है — collections.Counter, जो डिक्शनरी का ही एक विशेष प्रकार है:
from collections import Counter
words = ["refund", "late", "login", "refund", "login", "late", "slow"]
counts = Counter(words)
print(counts)
print(counts.most_common(2))
print(counts["missing"])Counter({'refund': 2, 'late': 2, 'login': 2, 'slow': 1})
[('refund', 2), ('late', 2)]
0Counter से किसी अनुपस्थित key को पढ़ने पर 0 मिलता है, न कि KeyError — जो गिनती के लिए बिल्कुल सही है। लेकिन most_common(2) को देखें: refund, late और login तीनों की गिनती 2 है, और पहले दो वापस आए। login क्यों छूट गया? क्योंकि समान गिनती के लिए, most_common उस क्रम को बनाए रखता है जिसमें शब्द पहली बार देखे गए थे। login सूची में तीसरे स्थान पर आया था, इसलिए वह बाहर हो गया। टिकट्स का क्रम बदलें और परिणाम भी बदल जाएगा — अध्याय की शुरुआत वाला यही रहस्य था।
टेक्स्ट साफ़ करना: कौन से शब्द वास्तव में शब्द हैं?
split() केवल खाली स्थान (whitespace) पर तोड़ता है:
text = "Refund not received. REFUND please! Login fails; login page is slow."
print(text.split())
print(text.lower().split())['Refund', 'not', 'received.', 'REFUND', 'please!', 'Login', 'fails;', 'login', 'page', 'is', 'slow.']
['refund', 'not', 'received.', 'refund', 'please!', 'login', 'fails;', 'login', 'page', 'is', 'slow.'].lower() ने छोटे/बड़े अक्षरों के अंतर को तो सुलझा दिया, लेकिन received., please! और slow. में अभी भी विराम चिह्न लगे हैं — और गिनती करते समय, slow. और slow दो अलग-अलग शब्द माने जाते हैं। यहीं रेगुलर एक्सप्रेशन (regex) काम आता है: क्या छोड़ना है यह कहने के बजाय, आप बताते हैं कि एक शब्द कैसा दिखता है:
import re
text = "Refund not received. REFUND please! Login fails; login page is slow. Can't pay."
words = re.findall(r"[a-z']+", text.lower())
print(words)['refund', 'not', 'received', 'refund', 'please', 'login', 'fails', 'login', 'page', 'is', 'slow', "can't", 'pay'][a-z']+ का अर्थ है "एक या अधिक छोटे अंग्रेज़ी अक्षर या अपॉस्ट्रॉफ़ी"। re.findall टेक्स्ट में पैटर्न से मेल खाने वाले प्रत्येक स्थान को लौटाता है, और बाकी सब कुछ — पूर्णविराम, अल्पविराम, अंक — छोड़ दिया जाता है। can't एक ही शब्द बना रहता है।
इस पैटर्न में एक कमी है: यदि कोई'invalid token'लिखता है, तो पहला शब्द'invalidबन जाता है — उद्धरण चिह्न (quote) साथ लगा हुआ। अगला उदाहरण पैटर्न को और कड़ा करता है ताकि अपॉस्ट्रॉफ़ी केवल दो अक्षरों के बीच ही आ सके। और याद रखें कि[a-z]केवल अंग्रेज़ी अक्षरों के लिए है; अन्य लिपियों के टेक्स्ट के लिए अलग पैटर्न की आवश्यकता होती है।
समान गिनती: सॉर्टिंग नियम खुद तय करें
गिनती को रैंकिंग में बदलने के लिए आपको सॉर्ट करना पड़ता है। ऐसी डिक्शनरी पर तीन तरीके जहाँ refund और login दोनों की गिनती 3 है:
counts = {"refund": 3, "late": 2, "login": 3, "slow": 1}
print(sorted(counts, reverse=True))
print(sorted(counts.items(), key=lambda item: item[1], reverse=True))
print(sorted(counts.items(), key=lambda item: (-item[1], item[0])))['slow', 'refund', 'login', 'late']
[('refund', 3), ('login', 3), ('late', 2), ('slow', 1)]
[('login', 3), ('refund', 3), ('late', 2), ('slow', 1)]पहली पंक्ति सबसे ख़तरनाक है, क्योंकि यह देखने में उचित लगती है। डिक्शनरी को सॉर्ट करने से उसकी keys सॉर्ट होती हैं, उसके मान नहीं — इसलिए यह उल्टा वर्णानुक्रम (reverse alphabetical order) है और इसका गिनती से कोई लेना-देना नहीं है। slow केवल एक बार आया था, फिर भी वह सबसे ऊपर है। कोई एरर नहीं आया।
दूसरी पंक्ति गिनती के अनुसार सॉर्ट करती है। लेकिन refund या login में से कौन पहले आएगा? पायथन का sorted "स्थिर (stable)" होता है — समान keys वाले तत्व इनपुट में मौजूद अपने मूल क्रम को बनाए रखते हैं। refund डिक्शनरी में पहले डाला गया था, इसलिए वह पहले आता है। दूसरे शब्दों में, परिणाम इस बात पर निर्भर करता है कि डेटा किस क्रम में आया था।
तीसरी पंक्ति स्पष्ट रूप से नियम तय करती है। key एक टपल लौटाता है, और टपल्स की तुलना तत्व-दर-तत्व होती है: पहले -item[1] — ऋणात्मक गिनती, ताकि बड़ी गिनती पहले आए — और टाई होने पर, item[0], यानी शब्द खुद, वर्णानुक्रम में। अब इनपुट चाहे जिस भी क्रम में आए, परिणाम हमेशा एक समान रहता है। यहाँ reverse=True की आवश्यकता नहीं है, क्योंकि ऋण चिह्न (-) ने गिनती के क्रम को उलट दिया है जबकि वर्णानुक्रम को वैसा ही रहने दिया है।
जहाँ भी परिणामों की तुलना की जाएगी — रिपोर्ट्स, टेस्ट्स, मूल्यांकन — समान मानों को व्यवस्थित करने के लिए एक स्पष्ट नियम ज़रूर दें। अन्यथा आज की रिपोर्ट और कल की रिपोर्ट में डेटा न बदलने पर भी अंतर दिखेगा।
एक संपूर्ण उदाहरण
अब सब कुछ एक साथ: टिकट्स में से टॉप पाँच शब्द निकालना। स्टॉप वर्ड्स — the और and जैसे शब्द जो हर टेक्स्ट में आते हैं लेकिन कोई खास अर्थ नहीं देते — हटा दिए जाते हैं, दो अक्षरों वाले शब्द हटा दिए जाते हैं, और टाई होने पर वर्णानुक्रम से फ़ैसला होता है। top_words.py:
import re
from collections import Counter
STOP_WORDS = {
"a", "and", "for", "i", "is", "it", "my", "not", "of", "on", "the", "to", "was", "with",
}
TICKETS = [
"Refund not received for order 1182. I was charged twice!",
"The app is slow and the login page freezes.",
"Charged twice again. Please refund the second charge.",
"Login fails with 'invalid token' on my phone.",
"Still waiting on my refund, it was promised last week.",
"App slow after the update; login takes a minute.",
]
def tokenize(text: str) -> list[str]:
return re.findall(r"[a-z]+(?:'[a-z]+)?", text.lower())
def top_words(texts: list[str], n: int = 5) -> list[tuple[str, int]]:
counts = Counter(
word
for text in texts
for word in tokenize(text)
if word not in STOP_WORDS and len(word) > 2
)
ranked = sorted(counts.items(), key=lambda item: (-item[1], item[0]))
return ranked[:n]
def print_ranking(ranking: list[tuple[str, int]]) -> None:
if not ranking:
print("no words to rank")
return
width = max(len(word) for word, _ in ranking)
for rank, (word, count) in enumerate(ranking, start=1):
print(f"{rank}. {word:<{width}} {count} {'#' * count}")
if __name__ == "__main__":
print_ranking(top_words(TICKETS))
print_ranking(top_words([]))uv run top_words.py1. login 3 ###
2. refund 3 ###
3. app 2 ##
4. charged 2 ##
5. slow 2 ##
no words to rankइसके पीछे के तकनीकी निर्णय:
शब्द पैटर्न [a-z]+(?:'[a-z]+)?। एक या अधिक अक्षर, फिर वैकल्पिक रूप से एक अपॉस्ट्रॉफ़ी और अधिक अक्षर। can't एक ही शब्द रहता है, लेकिन 'invalid token' के चारों ओर का उद्धरण चिह्न अब शब्द का हिस्सा नहीं बनता। (?:...) एक ऐसा समूह है जो कैप्चर नहीं होता — साधारण (...) के साथ, re.findall पूरे शब्द के बजाय केवल उस समूह के हिस्से को लौटाता।
स्टॉप वर्ड्स एक सेट हैं। प्रत्येक शब्द की जाँच word not in STOP_WORDS से की जाती है; सेट पर यह जाँच लगभग तात्कालिक होती है चाहे सूची कितनी भी लंबी क्यों न हो जाए।
Counter सीधे एक जनरेटर द्वारा पोषित होता है। दो for और एक if मिलकर एक स्ट्रीम बनाते हैं — प्रत्येक टिकट का प्रत्येक शब्द जो फ़िल्टर पास करता है। सभी शब्दों की कोई बड़ी मध्यवर्ती (intermediate) सूची नहीं बनाई जाती। दोनों for साधारण नेस्टेड लूप्स के क्रम में हैं: बाहरी लूप पहले।
एक स्पष्ट टाई-ब्रेक नियम। login और refund दोनों की गिनती 3 है; app, charged, slow और twice सभी की गिनती 2 है। वर्णानुक्रम ने तय किया कि किसे पाँचवाँ स्थान मिला, इसलिए twice बाहर हो गया। यह नियम भले ही परिपूर्ण न हो — twice कम महत्वपूर्ण होने के कारण बाहर नहीं हुआ — लेकिन यह घोषित है और हर बार एक ही रहता है। यदि रिपोर्ट पढ़ने वाला कोई व्यक्ति पूछे, तो आपके पास एक स्पष्ट उत्तर होता है।
खाली इनपुट को जानबूझकर संभाला गया है। खाली कलेक्शन पर max() चलाने से ValueError: max() iterable argument is empty आता है। बिना टिकट्स वाला शांत हफ़्ता सामान्य बात है, कोई एरर नहीं — इसलिए print_ranking पहले यह जांचती है कि रैंकिंग खाली तो नहीं है। दूसरी आउटपुट पंक्ति ठीक यही दर्शाती है।
गिनती और प्रदर्शन को अलग रखा गया है। top_words एक लिस्ट लौटाता है और कुछ भी प्रिंट नहीं करता; print_ranking केवल प्रिंट करता है। इसलिए उन्हीं गिनतियों का उपयोग किसी टेस्ट, API या डैशबोर्ड से भी किया जा सकता है। {word:<{width}} प्रत्येक शब्द को सबसे लंबे शब्द जितने स्थान में बाईं ओर अलाइन करता है, जिससे गिनती का कॉलम बिल्कुल सीध में रहता है।
एक सीमा: charged और charge यहाँ दो अलग-अलग शब्द हैं। किसी शब्द के विभिन्न रूपों को मिलाना अपने आप में एक अलग चुनौती है, और एआई सिस्टम आमतौर पर शब्दों को गिनने के बजाय उनके अर्थ से मिलान करते हैं — यह दृष्टिकोण कोर्स में आगे आएगा। लेकिन वहाँ भी, टेक्स्ट को साफ़ करना, फ़िल्टर करना और स्थिर क्रम में सॉर्ट करना — जो इस अध्याय का मुख्य काम है — पहला कदम होता है।
जब यह काम न करे
KeyError: 'refund' डिक्शनरी में अनुपस्थित key के लिए counts[word] += 1 लिखा गया। counts[word] = counts.get(word, 0) + 1 लिखें, या collections.Counter का उपयोग करें।
ValueError: too many values to unpack (expected 2) कोड में डिक्शनरी पर for key, value in d: लिखा गया है। डिक्शनरी पर सीधे लूप चलाने से केवल keys मिलती हैं; जोड़े (pairs) प्राप्त करने के लिए d.items() लिखें।
TypeError: unhashable type: 'list' किसी लिस्ट को सेट में डाल दिया गया या डिक्शनरी key के रूप में इस्तेमाल किया गया। सेट के तत्व और डिक्शनरी keys ऐसी चीज़ें होनी चाहिए जिन्हें बदला न जा सके (immutable)। लिस्ट के बजाय टपल का उपयोग करें: seen.add(("refund", "late"))।
RuntimeError: dictionary changed size during iteration डिक्शनरी पर लूप चलाते समय ही उससे keys हटाई गईं या जोड़ी गईं। सीधे हटाने के बजाय एक नई डिक्शनरी बनाएं: counts = {word: n for word, n in counts.items() if n >= 2}।
AttributeError: 'tuple' object has no attribute 'append' टपल बनने के बाद बदला नहीं जा सकता। यदि मान वास्तव में घटते-बढ़ते हैं, तो उसे लिस्ट होना चाहिए था; यदि टपल एक रिकॉर्ड है, तो नए मान के साथ एक नया टपल बनाएं।
ValueError: max() iterable argument is empty खाली कलेक्शन पर max() या min() चलाया गया। पहले जांचें कि क्या वह खाली है, या डिफ़ॉल्ट मान दें: max(lengths, default=0)।
चरण 4 / 6 — अनुमान
अपनी समझ की जाँच करें
A colleague is taking "the most frequent word" from a set of counts. What prints?
counts = {"refund": 5, "slow": 1, "login": 3}
print(sorted(counts, reverse=True)[0])- A`refund`
- B`('refund', 5)`
- C`slow`
- D`5`
label(2600) should return "critical", but it returns "slow" — with no error. Where is the bug?
def label(latency_ms):
if latency_ms >= 1000:
return "slow"
elif latency_ms >= 2000:
return "critical"
return "ok"
print(label(2600))- AThe order of the conditions: `>= 1000` is true first and the chain stops, so `>= 2000` is never reached — the strictest condition must come first
- B`return "ok"` needs an `else:` before it
- CThe second condition must use `if` instead of `elif`
- D`2600` is an integer, so it must be converted with `float()` before comparing with `>=`
A pipeline checks, for each of a million words, whether it is one of 300 stop words. Which container should hold the stop words?
- AA string, with all the words joined into one long text
- BA tuple, because stop words do not change
- CA set, because an `in` check is near-instant whatever its size
- DA list, because it can be kept in alphabetical order
प्ले प्रो का हिस्सा है
+30 XP इंतज़ार में
प्रो के साथ यह अध्याय खेलें
पढ़ना मुफ़्त है, और पूरा अध्याय खुला है। हर मुफ़्त कोर्स के पहले 5 अध्याय मुफ़्त में खेले जा सकते हैं। अध्याय 6 से प्रश्नों के उत्तर देना, XP कमाना और स्ट्रीक बढ़ाना प्रो का हिस्सा है।
प्रो से प्ले अनलॉक करेंआपकी बारी
अब प्रत्येक श्रेणी (category) के अनुसार टॉप शब्द खोजें। categories.py नामक फ़ाइल में, अध्याय के STOP_WORDS और tokenize को कॉपी करें, और ये टिकट्स जोड़ें:
TICKETS = [
("billing", "Charged twice for one order."),
("billing", "Refund for the double charge, please."),
("login", "Login fails on the new phone."),
("billing", "Still no refund after the charge."),
("login", "Password reset email never arrives."),
("login", "Login page shows a blank screen."),
]फिर ऐसा कोड लिखें जिससे:
- प्रत्येक श्रेणी की अपनी अलग गिनती हो — एक डिक्शनरी जिसकी keys श्रेणी के नाम हों और मान उस श्रेणी का
Counterहो (संकेत:dict.setdefaultऔरCounter.update) - स्टॉप वर्ड्स और दो या उससे कम अक्षरों वाले शब्दों को न गिना जाए
- प्रत्येक श्रेणी अपने शीर्ष दो शब्द दिखाए, अधिक गिनती पहले और टाई होने पर वर्णानुक्रम में
- श्रेणियाँ वर्णानुक्रम में प्रिंट हों, चाहे टिकट्स किसी भी क्रम में आएं
uv run categories.py को ठीक यह प्रिंट करना चाहिए:
billing charge=2, refund=2
login login=2, arrives=1फिर TICKETS सूची को उलट दें (TICKETS[::-1]) और इसे दोबारा चलाएं — क्या आउटपुट में कोई बदलाव आता है? यदि आता है, तो कौन सी शर्त पूरी नहीं हुई? अंत में, टाई-ब्रेक नियम हटा दें और केवल गिनती के आधार पर सॉर्ट करें: login के लिए दूसरा शब्द कौन सा आता है, और क्या क्रम उलटने पर वह वही रहता है?
चरण 6 / 6
चुनौती — अध्याय की क्विज़
सरल से कठिन — दस प्रश्न, अंतिम वाले जानबूझकर चुनौतीपूर्ण बनाए गए हैं।
प्रो के साथ खेलें