अध्याय 15

डिक्शनरी — की और मान के जोड़े

नाम से मान संग्रहीत करना और पाना, KeyError से बचने के लिए .get(), की जोड़ना-बदलना-हटाना, .items() से लूप चलाना, और लिस्ट की (key) क्यों नहीं हो सकती।

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

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

तीन लोगों के अंक संग्रहीत करने की आवश्यकता है — साथ में यह भी कि किसके अंक कौन से हैं।

लिस्ट केवल एक ही तरीका प्रदान करती है: दो सूचियाँ, समानांतर में।

python
names = ["rafi", "ahmed", "bilal"]
marks = [72, 45, 90]

print(names[1], marks[1])
text
ahmed 45

यह काम करता है। लेकिन पूरी व्यवस्था आपके अनुशासन पर टिकी है, जिसमें पायथन की कोई मदद नहीं है।

names में किसी को जोड़ें और marks को भूल जाएं? दोनों सूचियाँ अब अलग-अलग लंबाई की हैं, और वहाँ से names[2] और marks[2] दो अलग-अलग लोगों का वर्णन करते हैं। पायथन कुछ नहीं कहेगा। names को सॉर्ट करें? संबंध पूरी तरह और चुपचाप टूट जाता है।

जड़ यह है: दोनों चीज़ों के बीच का संबंध कहीं भी लिखा नहीं है। संबंध केवल "समान इंडेक्स" है — एक संयोग जो किसी भी क्षण टूट सकता है।

एक डिक्शनरी (Dictionary) इस संबंध को सीधे कोड में लिखती है। इंडेक्स के बजाय नाम, और दोनों की जोड़ी एक ही स्थान पर एक साथ बंधी होती है।

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

  • एक डिक्शनरी बनाना और उसकी की (key) द्वारा मान प्राप्त करना
  • .get() के साथ KeyError से बचना, और यह जानना कि कब किसका उपयोग करना सही है
  • की जोड़ना, बदलना और हटाना
  • .keys(), .values() और .items() के साथ डिक्शनरी पर लूप चलाना
  • यह समझाना कि कोई लिस्ट की (key) क्यों नहीं हो सकती लेकिन टपल हो सकता है

पूर्वापेक्षाएँ: टपल और अनपैकिंग.


डिक्शनरी — की (key) और मान (value) के जोड़े

मँझले कोष्ठक {} (curly brackets), अंदर key: value के जोड़े:

python
marks = {"rafi": 72, "ahmed": 45, "bilal": 90}

print(marks)
print(marks["ahmed"])
print(len(marks))
text
{'rafi': 72, 'ahmed': 45, 'bilal': 90}
45
3

marks["ahmed"] — एक नाम, इंडेक्स नहीं। और नाम सीधे कोड में है, इसलिए छह महीने बाद भी यह बताता है कि क्या मांगा जा रहा है।

len() जोड़ियों की गिनती करता है: तीन।

क्रम के बारे में: पायथन 3.7 के बाद से एक डिक्शनरी उस क्रम को याद रखती है जिसमें चीज़ें डाली गई थीं। लेकिन डिक्शनरी नाम द्वारा खोजने के लिए है, स्थिति द्वारा नहीं — marks[0] लिखें और पायथन शून्य संख्या वाली की की तलाश करेगा, नहीं मिलने पर रुक जाएगा।

ऐसी की (key) जो मौजूद नहीं है — KeyError और .get()

python
marks = {"rafi": 72}
print(marks["dia"])
text
KeyError: 'dia'

KeyError का अर्थ है "उस नाम से कोई की (key) नहीं है"। लिस्ट पर यही गलती IndexError देती थी।

क्रैश होने के बजाय एक सुरक्षित उत्तर पाने के लिए .get() का उपयोग करें:

python
marks = {"rafi": 72}

print(marks.get("dia"))
print(marks.get("dia", 0))
print(marks.get("rafi", 0))
text
None
0
72

दूसरा तर्क है "यदि यह गायब है तो मुझे यह मान दें"। इसके बिना आपको None मिलता है।

कौन सा, कब? यदि की को वहाँ होना ही चाहिए, तो marks["rafi"] लिखें — इसकी अनुपस्थिति एक बग है, और KeyError इसे तुरंत पकड़वा देगा। यदि की का न होना सामान्य बात है, तो .get() का उपयोग करें।

जोड़ना, बदलना, हटाना

python
marks = {"rafi": 72}

marks["dia"] = 88
marks["rafi"] = 75

print(marks)

del marks["rafi"]
print(marks)
text
{'rafi': 75, 'dia': 88}
{'dia': 88}

वही पंक्ति दो काम करती है: यदि की अनुपस्थित है तो इसे जोड़ दिया जाता है, और यदि यह मौजूद है तो इसे बदल दिया जाता है। कोई अलग "add" मेथड नहीं है।

और इसी से एक महत्वपूर्ण नियम निकलता है — एक की केवल एक बार आ सकती है:

python
marks = {"rafi": 72, "rafi": 90}
print(marks)
text
{'rafi': 90}

कोई त्रुटि नहीं। दूसरे ने चुपचाप पहले वाले को मिटा दिया।

in कीज़ (keys) को खोजता है, मानों (values) को नहीं

python
marks = {"rafi": 72, "ahmed": 45}

print("rafi" in marks)
print(72 in marks)
text
True
False

72 निश्चित रूप से एक मान के रूप में मौजूद है, लेकिन in केवल keys के बीच देखता है। मानों को खोजने के लिए आपको स्पष्ट रूप से कहना होगा: 72 in marks.values()।

इस पर लूप चलाना — तीन तरीके

python
marks = {"rafi": 72, "ahmed": 45}

for name in marks:
    print(name)

print("---")
for name, mark in marks.items():
    print(name, mark)

print("---")
print(list(marks.keys()))
print(list(marks.values()))
text
rafi
ahmed
---
rafi 72
ahmed 45
---
['rafi', 'ahmed']
[72, 45]

पहला ध्यान देने योग्य है: for name in marks आपको keys देता है, मान नहीं।

जब आप दोनों चाहते हैं, तो .items() हर बार एक टपल देता है — और name, mark उसे अनपैक करता है।

मानों पर गणना करने के लिए, .values():

python
marks = {"rafi": 72, "ahmed": 45, "bilal": 90}

print(sum(marks.values()))
print(max(marks.values()))
print(round(sum(marks.values()) / len(marks), 2))
text
207
90
69.0

कौन सी चीज़ की (key) बन सकती है

की बनने के लिए किसी वस्तु का अपरिवर्तनीय (immutable) होना आवश्यक है। टेक्स्ट, संख्याएँ और टपल सभी काम करते हैं। लिस्ट काम नहीं करती:

python
d = {}
d[["a", "b"]] = 1
text
TypeError: unhashable type: 'list'

"unhashable" शब्द का अर्थ: एक डिक्शनरी चीज़ों को इतनी तेज़ी से ढूँढती है क्योंकि वह प्रत्येक की से एक संख्या की गणना करती है और उस संख्या का उपयोग सीधे सही स्थान पर जाने के लिए करती है। यदि की बाद में बदल सकती है, तो वह संख्या गलत हो जाएगी और प्रविष्टि खो जाएगी। इसलिए पायथन किसी भी परिवर्तनशील चीज़ को की बनने से साफ़ मना कर देता है।

एक टपल बदल नहीं सकता, जो इसे एक उत्कृष्ट की बनाता है:

python
grid = {}
grid[(0, 0)] = "start"
grid[(1, 2)] = "tree"

print(grid)
print(grid[(1, 2)])
text
{(0, 0): 'start', (1, 2): 'tree'}
tree

सबसे उपयोगी पैटर्न — गिनती करना

python
words = ["pen", "bag", "pen", "ink", "pen"]
counts = {}

for word in words:
    counts[word] = counts.get(word, 0) + 1

print(counts)
text
{'pen': 3, 'bag': 1, 'ink': 1}

पंक्ति को अंदर से पढ़ें: counts.get(word, 0) कहता है "मुझे अब तक की इस शब्द की गिनती दें, और शून्य दें यदि अभी तक कोई नहीं है", फिर एक जोड़ा जाता है और परिणाम वापस रख दिया जाता है।


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

marks.py:

python
# एक डिक्शनरी एक नाम को उसके मान के साथ जोड़कर रखती है
marks = {"rafi": 72, "ahmed": 45, "bilal": 90, "dia": 88}

print("Everyone:")
for name, mark in marks.items():
    status = "pass" if mark >= 40 else "fail"
    print(f"  {name:<8} {mark:>3}  {status}")

print()
print("Count    :", len(marks))
print("Total    :", sum(marks.values()))
print("Average  :", round(sum(marks.values()) / len(marks), 2))
print("Highest  :", max(marks.values()))

best = max(marks, key=marks.get)
print("Best     :", best, marks[best])

print("Has dia  :", "dia" in marks)
print("Missing  :", marks.get("nadia", "not recorded"))

marks["dia"] = 91
marks["nadia"] = 60
del marks["ahmed"]

print()
print("After edits:", marks)
text
Everyone:
  rafi      72  pass
  ahmed     45  pass
  bilal     90  pass
  dia       88  pass

Count    : 4
Total    : 295
Average  : 73.75
Highest  : 90
Best     : bilal 90
Has dia  : True
Missing  : not recorded

After edits: {'rafi': 72, 'bilal': 90, 'dia': 91, 'nadia': 60}

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

status = "pass" if mark >= 40 else "fail" एक पंक्ति में शर्त लिखने का एक तरीका है।

max(marks, key=marks.get) अध्याय 13 का key= एक नया काम कर रहा है। max(marks) सबसे बड़ी की देता, यानी वर्णमाला के अनुसार अंतिम नाम। key=marks.get इसके बजाय प्रत्येक की की उसके मान से तुलना करने को कहता है, जो उच्चतम अंक वाले नाम को देता है।

अंतिम पंक्ति पर क्रम: dia पहले से मौजूद थी, इसलिए उसका मान बदला लेकिन उसकी स्थिति नहीं। nadia नई है, इसलिए इसे अंत में जोड़ा गया। और ahmed चला गया।


जब यह टूटता है

KeyError: 'dia' उस नाम से कोई की नहीं है। वर्तनी और केस की जाँच करें — "Rafi" और "rafi" दो अलग-अलग की हैं। यदि अनुपस्थिति सामान्य है, तो .get() का उपयोग करें।

TypeError: unhashable type: 'list' लिस्ट को की के रूप में उपयोग करने का प्रयास। टपल का उपयोग करें — tuple(my_list) एक बनाता है।

for x in my_dict मुझे मान नहीं दे रहा है यह केवल keys देता है। मानों के लिए .values() का उपयोग करें, और दोनों के लिए .items()।

दो कीज़ एक जैसी थीं और एक रिकॉर्ड गायब हो गया एक की केवल एक बार मौजूद हो सकती है, और बाद वाली ने पहले वाली को चुपचाप बदल दिया। एक नाम के तहत कई रिकॉर्ड रखने के लिए मान को एक लिस्ट बनाएं — अध्याय 17 का विषय।