लिस्ट — एक ही नाम में कई वैल्यू
एक नाम में जितनी चाहें उतनी वैल्यू रखना, इंडेक्स और स्लाइस से अंदर तक पहुँचना, लिस्ट बदलने वाले मेथड — और दो नामों के एक ही लिस्ट से जुड़ने का जाल।
आप कैसे सीखना चाहते हैं?
वह समस्या जिसे हम हल कर रहे हैं
एक दुकान के तीन प्रोडक्ट की क़ीमत रखनी है। अब तक जो सीखा है, उसमें तरीक़ा एक ही है:
price_1 = 15
price_2 = 60
price_3 = 850
print(price_1 + price_2 + price_3)925अब सवाल: प्रोडक्ट चालीस हों तो? चालीस वेरिएबल। और जोड़ने वाली लाइन चालीस टुकड़ों की। और दुकान में एक नया प्रोडक्ट आए तो कोड में जाकर नया वेरिएबल बनाना पड़ेगा।
समस्या सिर्फ़ मेहनत की नहीं, ढाँचे की भी है। price_1, price_2, price_3 — Python के लिए ये तीन नाम पूरी तरह अलग-अलग हैं, ठीक वैसे ही जैसे name और age। लेकिन आप जानते हैं कि ये एक ही चीज़ के तीन उदाहरण हैं। "एक ही चीज़ के कई" वाली बात कोड में लिखने का कोई तरीक़ा अभी हमारे पास नहीं है।
लिस्ट वही तरीक़ा है। एक नाम, उसके नीचे जितनी चाहें उतनी वैल्यू, क्रम बना रहता है।
इस अध्याय के बाद आप यह कर पाएँगे
- लिस्ट बनाना, और इंडेक्स व स्लाइस से उसके अंदर पहुँचना
append,insert,remove,popसे लिस्ट बदलना- बताना कि लिस्ट क्यों बदली जा सकती है जबकि स्ट्रिंग नहीं
b = aलिखने पर दो नाम एक ही लिस्ट से जुड़ जाते हैं — इसे पहचानना और इससे बचनाIndexErrorऔरValueErrorपढ़कर समझना कि क्या ग़लत हुआ
पहले यह आना चाहिए: for लूप और range।
एक लिस्ट बनाना
स्क्वेयर ब्रैकेट, और अंदर कॉमा से अलग की गई वैल्यू:
prices = [15, 60, 850]
print(prices)
print(len(prices))[15, 60, 850]
3len() यहाँ भी चलता है, बिल्कुल स्ट्रिंग की तरह — तीन वैल्यू, इसलिए 3।
प्रिंट करने पर स्क्वेयर ब्रैकेट समेत पूरी लिस्ट दिखती है। यह यूज़र के पढ़ने के लिए नहीं, आपके समझने के लिए है: [15, 60, 850] देखकर पता चलता है कि यह एक लिस्ट है, 925 नहीं।
अंदर पहुँचना
स्ट्रिंग का इंडेक्स जैसे काम करता था, बिल्कुल वैसे ही — शून्य से शुरू, पीछे से नेगेटिव:
prices = [15, 60, 850]
print(prices[0])
print(prices[-1])
print(prices[1:])15
850
[60, 850]तीनों लाइनें अध्याय 6 के नियम हैं, कुछ नया नहीं। बस एक फ़र्क़ ध्यान देने लायक़ है: prices[0] एक नंबर देता है, लेकिन prices[1:] एक लिस्ट देता है — स्लाइस हमेशा उसी तरह की चीज़ लौटाता है जिससे काटा गया, कभी एक अकेला टुकड़ा नहीं।
अब असली फ़र्क़: लिस्ट बदली जा सकती है
अध्याय 6 में देखा था कि स्ट्रिंग के अंदर का एक अक्षर नहीं बदला जा सकता:
name = "rafi"
name[0] = "R"TypeError: 'str' object does not support item assignmentलिस्ट में ठीक यही लाइन चलती है:
prices = [15, 60, 850]
prices[0] = 20
print(prices)[20, 60, 850]कोई नई लिस्ट नहीं बनी — यही लिस्ट बदल गई। यह लिस्ट की सबसे अहम ख़ासियत है, और इस अध्याय के आख़िर वाला जाल भी यहीं से आता है।
टेक्निकल शब्दों में: स्ट्रिंग immutable (बदली नहीं जा सकती) है, लिस्ट mutable (बदली जा सकती) है।
जोड़ना और हटाना
stock = ["pen", "notebook"]
stock.append("bag")
stock.insert(1, "eraser")
print(stock)
stock.remove("pen")
print(stock)
last = stock.pop()
print(last)
print(stock)['pen', 'eraser', 'notebook', 'bag']
['eraser', 'notebook', 'bag']
bag
['eraser', 'notebook']चार मेथड, चार अलग काम:
append(x)— आख़िर में जोड़ता हैinsert(i, x)—iनंबर की जगह पर डालता है, बाक़ियों को दाईं ओर खिसकाकरremove(x)— वैल्यू से ढूँढकर पहली वाली हटाता हैpop()— आख़िरी वाली हटाता है और लौटाता है
आख़िरी दो का फ़र्क़ ध्यान से देखिए, क्योंकि ज़्यादातर उलझन यहीं होती है: remove जानना चाहता है क्या हटाना है, pop जानना चाहता है कहाँ से। और pop हटाई गई चीज़ आपके हाथ में देता है, remove नहीं देता।
ये मेथड कुछ नहीं लौटाते। स्ट्रिंग मेंname.upper()का नतीजा पकड़कर रखना पड़ता था, क्योंकि वह नई स्ट्रिंग बनाकर लौटाता था। लिस्ट में ठीक उल्टा:appendअसली लिस्ट को ही बदल देता है, और लौटाता हैNone।
इसलिए यह लाइन एक क्लासिक ग़लती है:
stock = ["pen", "notebook"]
stock = stock.append("bag")
print(stock)Noneलिस्ट खो गई। stock.append("bag") लिखिए, stock = stock.append("bag") नहीं।
ढूँढना और लूप चलाना
stock = ["pen", "notebook", "bag"]
print("pen" in stock)
print("chair" in stock)
for item in stock:
print(item.upper())True
False
PEN
NOTEBOOK
BAGin स्ट्रिंग के अंदर ढूँढता था, लिस्ट में भी ढूँढता है — वही शब्द, वही काम।
और for item in stock लिस्ट की हर वैल्यू पर एक-एक करके चलता है। ध्यान दीजिए, यहाँ range नहीं लगा, इंडेक्स का हिसाब भी नहीं करना पड़ा — अध्याय 11 में स्ट्रिंग के अक्षरों पर जैसे चले थे, हूबहू वैसे ही।
पोज़िशन (इंडेक्स) और वैल्यू दोनों चाहिए तो enumerate:
stock = ["pen", "notebook"]
for position, item in enumerate(stock, start=1):
print(position, item)1 pen
2 notebookstart=1 न दें तो गिनती शून्य से शुरू होती है। लोगों को दिखाई जाने वाली सूची आमतौर पर एक से ही शुरू करनी होती है।
वह जाल जो सबसे ज़्यादा परेशान करता है
अध्याय 4 में देखा था:
a = 3
b = a
b = b + 1
print(a, b)3 4b को वैल्यू मिली थी, वह a की तरफ़ नहीं देख रहा था। अब लिस्ट के साथ यही करके देखिए:
a = [1, 2, 3]
b = a
b.append(4)
print(a)
print(b)[1, 2, 3, 4]
[1, 2, 3, 4]b बदला गया था, लेकिन a भी बदल गया।
वजह पुराने नियम के ख़िलाफ़ नहीं, बल्कि वही नियम है। b = a लाइन पर b को वही मिला जो a में था — और a में था लिस्ट का पता, लिस्ट की कॉपी नहीं। इसलिए दोनों नाम अब एक ही लिस्ट की तरफ़ इशारा कर रहे हैं। b.append(4) ने उसी एक लिस्ट को बदला, और दोनों नामों से वही बदलाव दिखता है।
नंबरों में यह नज़र नहीं आता, क्योंकि b = b + 1 पुराने नंबर को नहीं बदलता — वह एक नया नंबर बनाकर b में रखता है। बदला नहीं जा सकता, इसीलिए नंबर सुरक्षित है। लिस्ट बदली जा सकती है, इसलिए लिस्ट नहीं।
अलग कॉपी चाहिए तो माँगनी पड़ती है:
a = [1, 2, 3]
b = a.copy()
b.append(4)
print(a)
print(b)[1, 2, 3]
[1, 2, 3, 4]कब सावधान रहें। जब भी किसी लिस्ट को दूसरे नाम में रख रहे हों, या किसी लिस्ट को फ़ंक्शन में भेज रहे हों (अध्याय 19), एक बार खुद से पूछिए: मैं इसी को बदलना चाहता हूँ, या एक कॉपी चाहिए? जो यह सवाल नहीं पूछते, वे दिनों तक "मैंने तो यहाँ कुछ बदला ही नहीं" वाले बग ढूँढते रहते हैं।
एक पूरा उदाहरण
shopping.py:
# A shopping list, built up and then summarised
items = []
items.append("pen")
items.append("notebook")
items.append("bag")
items.insert(0, "eraser")
print("List :", items)
print("Count :", len(items))
print("First :", items[0])
print("Last :", items[-1])
print("Has bag :", "bag" in items)
items.remove("pen")
dropped = items.pop()
print()
print("After removing 'pen' and popping the last one:")
print("List :", items)
print("Dropped :", dropped)
print("Count :", len(items))
print()
print("Numbered:")
for position, item in enumerate(items, start=1):
print(f" {position}. {item}")List : ['eraser', 'pen', 'notebook', 'bag']
Count : 4
First : eraser
Last : bag
Has bag : True
After removing 'pen' and popping the last one:
List : ['eraser', 'notebook']
Dropped : bag
Count : 2
Numbered:
1. eraser
2. notebookतीन बातें ध्यान देने लायक़ हैं।
शुरुआत ख़ाली लिस्ट से। items = [] लाइन लूप के बाहर वाले एक्यूमुलेटर जैसी ही है — अध्याय 10 में total = 0 जो काम करता था, यहाँ [] वही कर रहा है। जमा करने से पहले जमा करने की जगह होनी चाहिए।
insert(0, "eraser") ने उसे सबसे आगे रखा, इसलिए प्रिंट हुई सूची में eraser पहले है — जोड़ने का क्रम और सूची का क्रम एक नहीं है।
pop() ने हटाई गई चीज़ लौटा दी, इसलिए dropped में bag है। remove("pen") ने कुछ नहीं लौटाया, इसलिए हटाया गया pen अब कहीं नहीं है।
कुछ टूटी हुई हालतें और उनका हल
IndexError: list index out of range लिस्ट में जितनी वैल्यू हैं, उसके बाहर का इंडेक्स माँगा गया। तीन वैल्यू वाली लिस्ट में सही इंडेक्स 0, 1, 2 हैं — prices[3] नहीं है। आख़िरी वैल्यू चाहिए तो prices[-1] सबसे सुरक्षित है, क्योंकि लंबाई जानने की ज़रूरत नहीं पड़ती।
ValueError: list.remove(x): x not in list जो वैल्यू हटाने को कहा, वह लिस्ट में है ही नहीं। पहले if x in stock: से देख लीजिए, या फिर अध्याय 24 का try इस्तेमाल कीजिए।
AttributeError: 'NoneType' object has no attribute 'append' किसी पिछली लाइन में stock = stock.append(...) लिखा गया है, इसलिए stock अब None है। नतीजा पकड़कर मत रखिए — stock.append(...) काफ़ी है।
एक लिस्ट बदली, दूसरी भी बदल गई दो नाम एक ही लिस्ट से जुड़े हैं। b = a नहीं, b = a.copy() लिखिए।
लूप के अंदर हटा रहा हूँ, कुछ छूट जा रहे हैं
numbers = [1, 2, 2, 3, 4]
for n in numbers:
if n % 2 == 0:
numbers.remove(n)
print(numbers)[1, 2, 3]एक 2 बच गया। जिस लिस्ट पर चल रहे हैं उसी को छोटा करें तो Python की गिनती और लिस्ट की पोज़िशन मेल नहीं खातीं, इसलिए कुछ वैल्यू छूट जाती हैं। हल: हटाइए मत, जो रखनी हैं उन्हें एक नई लिस्ट में रखिए।
numbers = [1, 2, 2, 3, 4]
kept = []
for n in numbers:
if n % 2 != 0:
kept.append(n)
print(kept)[1, 3]list नाम का वेरिएबल बनाया, अब list(...) काम नहीं कर रहा list Python का अपना नाम है। items, prices, names — मतलब वाले नाम दीजिए।
चरण 4 / 6 — अनुमान
अपनी समझ की जाँच करें
append का नतीजा फिर से stock में रखा गया है। क्या प्रिंट होगा?
stock = ["pen", "notebook"]
stock = stock.append("bag")
print(stock)- ANone
- B['pen', 'notebook', 'bag']
- C['bag']
- Dएक `AttributeError`
सिर्फ़ b बदला गया है। दोनों लाइनें क्या प्रिंट करेंगी?
a = [1, 2, 3]
b = a
b.append(4)
print(a)
print(b)- A[1, 2, 3] [4]
- B[1, 2, 3] [1, 2, 3, 4]
- C[1, 2, 3, 4] [1, 2, 3]
- D[1, 2, 3, 4] [1, 2, 3, 4]
लिस्ट में तीन वैल्यू हैं, और इंडेक्स तीन माँगा गया है। क्या होगा?
prices = [15, 60, 850]
print(prices[3])- Aएक ख़ाली लिस्ट
- B`IndexError` — तीन वैल्यू के सही इंडेक्स `0`, `1`, `2` हैं
- CNone
- D850 — आख़िरी वैल्यू
उत्तर देने के लिए अकाउंट आवश्यक है
अपने उत्तर जाँचने के लिए साइन इन करें
प्रश्न ऊपर दिए गए हैं, और मन में उत्तर सोचना ही मुख्य कार्य है। सही उत्तर, व्याख्या और तीन-स्तरीय संकेत देखने के लिए साइन इन करें।
आपकी बारी
marks.py नाम की एक फ़ाइल लिखिए, जिसमें कम से कम छह लोगों के नंबरों की एक लिस्ट हो।
फिर प्रिंट कीजिए:
- पूरी लिस्ट, और उसमें कितने नंबर हैं
- पहला और आख़िरी नंबर — आख़िरी के लिए
[-1]इस्तेमाल कीजिए - जोड़ और औसत (लूप से जमा कीजिए, हाथ से मत लिखिए)
enumerateसे एक से शुरू होने वाली नंबर वाली सूची- पास हुए नंबरों (40 या ज़्यादा) की एक नई लिस्ट, और उसमें कितने हैं
फिर दो प्रयोग कीजिए, और दोनों ज़रूरी हैं:
- लिस्ट के आख़िर में एक नंबर
appendकीजिए, फिर जोड़ दोबारा प्रिंट कीजिए। क्या जोड़ वाली लाइन बदलनी पड़ी? नहीं, तो आपने असली हिसाब लिखा है। backup = marksलिखकर फिरmarks.append(100)कीजिए, और दोनों प्रिंट कीजिए।backupमें क्या दिख रहा है? अब.copy()से यही काम करके फ़र्क़ देखिए।
आख़िरी प्रयोग इस अध्याय के सबसे क़ीमती तीन मिनट हैं। इसे एक बार अपनी आँखों से देख लिया, तो बाद में पकड़ने में वक़्त नहीं लगेगा।
चरण 6 / 6
चुनौती — अध्याय की क्विज़
सरल से कठिन — दस प्रश्न, अंतिम वाले जानबूझकर चुनौतीपूर्ण बनाए गए हैं।
क्विज़ देने के लिए साइन इन करें