টাপল আর আনপ্যাকিং
বদলানো যায় না এমন লিস্ট — কোথায় সেটাই দরকার, আনপ্যাকিং দিয়ে সূচকের বদলে নাম ব্যবহার, এক লাইনে অদলবদল, আর (5) বনাম (5,)-এর ফাঁদ।
- 1সমস্যা
- 2বোঝা
- 3উদাহরণ
- 4অনুমান
- 5নিজে করা
- 6কঠিন করা
যে সমস্যাটা আমরা সমাধান করছি
তিন দিনের আবহাওয়ার হিসাব রাখতে হবে — প্রতিদিনের দিন, তাপমাত্রা আর আর্দ্রতা।
লিস্ট দিয়ে করা যায়: ["monday", 31.5, 78]। কাজ চলবে, কিন্তু দুটো জিনিস খচখচ করে।
প্রথমত, এই লিস্টটা বদলানো যায়। সোমবারের রেকর্ডে কেউ ভুল করে append করে বসলে পাইথন কিছুই বলবে না — অথচ একটা রেকর্ডে চারটি জিনিস থাকার কথাই নয়। যে জিনিসটা বদলানোর কথা নয়, তাকে বদলানো যায় এমন পাত্রে রাখা একটা নীরব ঝুঁকি।
দ্বিতীয়ত, ভেতর থেকে তিনটি মান বের করতে হলে লিখতে হয় record[0], record[1], record[2] — সংখ্যা দিয়ে, নাম দিয়ে নয়। ছয় মাস পর record[1] পড়ে কেউ বুঝবে না ওটা তাপমাত্রা না আর্দ্রতা।
টাপল দুটোরই উত্তর: এটি একটি লিস্ট, কিন্তু বদলানো যায় না — আর তার সাথে আসে একটি সুবিধা, যার নাম আনপ্যাকিং, যা সূচকের বদলে নাম ব্যবহার করতে দেয়।
এই অধ্যায় শেষে আপনি পারবেন
- টাপল বানাতে, আর বলতে কোথায় লিস্ট নয় টাপল লাগে
- আনপ্যাকিং দিয়ে কয়েকটি মান একসাথে কয়েকটি নামে বসাতে
- এক লাইনে দুটি ভেরিয়েবলের মান অদলবদল করতে
(5)আর(5,)-এর পার্থক্য ধরতে- টাপলের উপর
appendকরতে গেলে কেনAttributeErrorআসে, বলতে
আগে যা জানা লাগবে: লিস্ট সাজানো আর তার মেথডগুলো।
টাপল — বদলানো যায় না এমন লিস্ট
বর্গবন্ধনীর বদলে সাধারণ বন্ধনী:
point = (3, 7)
print(point)
print(point[0])
print(len(point))(3, 7)
3
2পড়া, সূচক, len, স্লাইস, in, for দিয়ে ঘোরা — লিস্টে যা যা করতেন সবই চলে। পার্থক্য একটাই, আর সেটাই সব:
point = (3, 7)
point[0] = 5TypeError: 'tuple' object does not support item assignmentবার্তাটা চেনা লাগছে? ষষ্ঠ অধ্যায়ে লেখার ভেতরের অক্ষর বদলাতে গিয়ে ঠিক এই বার্তাটাই এসেছিল, শুধু 'str' লেখা ছিল। পাইথনে অপরিবর্তনীয় জিনিসগুলো একই ভাষায় অভিযোগ করে।
বদলানোর মেথডগুলোও নেই:
point = (3, 7)
point.append(9)AttributeError: 'tuple' object has no attribute 'append'AttributeError মানে «এই ধরনের জিনিসের এমন কোনো মেথড নেই»। টাপল বদলানো যায় না, তাই বদলানোর মেথডগুলো তার নেই — TypeError নয়, কারণ সমস্যাটা কাজটার নয়, জিনিসটার।
কেন এটা সুবিধা, বাধা নয়
প্রথমে মনে হয় টাপল হলো কম ক্ষমতার লিস্ট। উল্টো করে ভাবুন: যে জিনিসটা বদলানোর কথা নয়, তাকে বদলানো যায় না এমন পাত্রে রাখলে ভুলটা ঘটার আগেই আটকে যায়।
একটি স্থানাঙ্ক (3, 7)-এ তৃতীয় সংখ্যা যোগ করার মানে হয় না। একটি তারিখ (2026, 9, 16)-এ চতুর্থ কিছু থাকার কথা নয়। এই জিনিসগুলো টাপলে রাখলে দুর্ঘটনাটা ত্রুটি হয়ে সাথে সাথে ধরা পড়ে, বাগ হয়ে পরে নয়।
নিয়ম হিসেবে: কয়টি জিনিস আর তাদের অর্থ আগে থেকেই ঠিক — টাপল। কয়টি হবে জানা নেই, আর সবগুলো একই জাতের — লিস্ট।
তিন দিনের আবহাওয়া তাই লিস্টের ভেতরে টাপল: কয়টি দিন হবে জানা নেই (লিস্ট), কিন্তু প্রতিটি রেকর্ডে ঠিক তিনটি জিনিস (টাপল)।
আনপ্যাকিং — আসল সুবিধাটা এখানে
point = (3, 7)
x, y = point
print(x)
print(y)3
7এক লাইনে দুটি নাম, দুটি মান। আর এখন point[1] নয়, y — যে নামটা পড়লেই বোঝা যায়।
বাঁ পাশে যতগুলো নাম, ডান পাশে ঠিক ততগুলো মান থাকতে হবে:
point = (3, 7)
x, y, z = pointValueError: not enough values to unpack (expected 3, got 2)বার্তাটা অস্বাভাবিক রকম সহায়ক — কয়টি আশা করা হয়েছিল আর কয়টি পাওয়া গেছে, দুটোই বলে দেয়।
আনপ্যাকিং টাপলেই সীমাবদ্ধ নয়, লিস্টেও চলে। কিন্তু সবচেয়ে বেশি কাজে লাগে টাপলের সাথেই, কারণ টাপলেই সংখ্যাটা আগে থেকে জানা।
অদলবদল — এক লাইনে
অন্য ভাষায় দুটি ভেরিয়েবলের মান বদলাবদলি করতে একটি অস্থায়ী তৃতীয় ভেরিয়েবল লাগে। পাইথনে লাগে না:
a = 1
b = 2
a, b = b, a
print(a, b)2 1লাইনটি কীভাবে কাজ করে সেটা বোঝা জরুরি: পাইথন আগে ডান পাশটা পুরো হিসাব করে, একটি টাপল (2, 1) বানায়, তারপর সেটিকে বাঁ পাশে আনপ্যাক করে। তাই a বদলে গেলেও b-এর পুরোনো মান ততক্ষণে ধরা আছে, আর কিছু হারায় না।
বন্ধনী আসলে বাধ্যতামূলক নয়
point = 3, 7
print(point)
print(type(point))(3, 7)
<class 'tuple'>টাপল তৈরি করে কমা, বন্ধনী নয়। বন্ধনী কেবল পড়ার সুবিধার জন্য। এটা জানা থাকলে a, b = b, a লাইনটা আর জাদু মনে হয় না — ডান পাশে b, a একটি টাপলই।
আর এখান থেকেই একটি ফাঁদ আসে:
one = (5)
really = (5,)
print(type(one))
print(type(really))
print(len(really))<class 'int'>
<class 'tuple'>
1(5) কোনো টাপল নয় — ওটা কেবল বন্ধনীতে মোড়া একটি সংখ্যা, ঠিক যেমন (2 + 3)। একটিমাত্র মানের টাপল বানাতে হলে কমা লাগবেই: (5,)। দেখতে টাইপো লাগে, কিন্তু ওই কমাটাই পুরো পার্থক্য।
লুপে টাপল
people = [("rafi", 22), ("ahmed", 35)]
for name, age in people:
print(f"{name} is {age}")rafi is 22
ahmed is 35for name, age in people প্রতিটি টাপলকে সরাসরি দুটি নামে আনপ্যাক করে দিচ্ছে। person[0] আর person[1] লেখার দরকার নেই — আর কোডটা পড়লেই বোঝা যায় কোনটা কী।
এই কৌশলটা আপনি আগেই ব্যবহার করেছেন, না জেনে:
stock = ["pen", "bag"]
for pair in enumerate(stock):
print(pair)(0, 'pen')
(1, 'bag')enumerate আসলে টাপলই দেয়। গত অধ্যায়ে for position, item in enumerate(...) লিখে আমরা সেই টাপলগুলোকে আনপ্যাক করছিলাম — তখন নামই জানতাম না।
এদিক-ওদিক বদলানো
as_list = [3, 7]
as_tuple = (3, 7)
as_list.append(9)
print(as_list)
print(as_tuple)
print(list(as_tuple))
print(tuple(as_list))[3, 7, 9]
(3, 7)
[3, 7]
(3, 7, 9)list() আর tuple() একটি থেকে অন্যটি বানায় — নতুন একটি জিনিস বানায়, পুরোনোটা অক্ষত থাকে। একটি টাপল «বদলাতে» হলে এটাই উপায়: লিস্ট বানান, বদলান, আবার টাপল বানান।
একটা সম্পূর্ণ উদাহরণ
weather.py:
# A tuple is the right shape for a record that must not change
readings = [
("monday", 31.5, 78),
("tuesday", 33.0, 71),
("wednesday", 29.5, 85),
]
print("Day Temp Humidity")
for day, temp, humidity in readings:
print(f"{day:<10} {temp:>5} {humidity:>5}")
hottest = readings[0]
for reading in readings:
if reading[1] > hottest[1]:
hottest = reading
day, temp, humidity = hottest
print()
print(f"Hottest was {day} at {temp}")
temps = []
for _, temp, _ in readings:
temps.append(temp)
print("Temps :", temps)
print("Average :", round(sum(temps) / len(temps), 2))Day Temp Humidity
monday 31.5 78
tuesday 33.0 71
wednesday 29.5 85
Hottest was tuesday at 33.0
Temps : [31.5, 33.0, 29.5]
Average : 31.33চারটি জিনিস লক্ষ করার মতো।
বাইরে লিস্ট, ভেতরে টাপল। দিনের সংখ্যা বাড়তে পারে, তাই বাইরেরটা লিস্ট। প্রতিটি রেকর্ডে ঠিক তিনটি জিনিস, তাই ভেতরেরগুলো টাপল। এটাই বাস্তব ডেটার সবচেয়ে সাধারণ আকার।
f"{day:<10}" আর f"{temp:>5}" — কলাম সোজা রাখার জন্য। < বাঁয়ে ঘেঁষায়, > ডানে, আর সংখ্যাটা কত ঘর জায়গা নেবে তা বলে। ষষ্ঠ অধ্যায়ের :.2f-এর মতোই, কোলনের পরের অংশটুকু কেবল সাজসজ্জা।
সবচেয়ে গরম দিনটা খুঁজতে reading[1] লিখতে হয়েছে, কারণ তুলনার সময় গোটা টাপলটাই হাতে আছে, আনপ্যাক করা নয়। পাওয়ার পর সাথে সাথেই আনপ্যাক করা হয়েছে — তাই তার পরের লাইনে আর সূচক নেই।
for _, temp, _ in readings — আন্ডারস্কোরটি একটি প্রচলিত রীতি, যার অর্থ «এই মানটা লাগবে না»। পাইথনের কাছে এটি আর দশটা নামের মতোই, কিন্তু পড়ার সময় এটি বলে দেয় কোন অংশটুকু ইচ্ছে করে ফেলে দেওয়া হচ্ছে।
কিছু ভাঙা অবস্থা ও তার সমাধান
TypeError: 'tuple' object does not support item assignment টাপলের ভেতরের একটি মান বদলানোর চেষ্টা। টাপল বদলানো যায় না — হয় শুরুতেই লিস্ট ব্যবহার করুন, নয়তো list(...) দিয়ে বদলে নিয়ে কাজ করুন।
AttributeError: 'tuple' object has no attribute 'append' একই কারণ, অন্য চেহারায়। append, remove, sort — বদলানোর কোনো মেথডই টাপলের নেই। তবে sorted(my_tuple) কাজ করে, কারণ সে নতুন একটি লিস্ট ফেরত দেয়, টাপলটাকে ছোঁয় না।
ValueError: not enough values to unpack (expected 3, got 2) বাঁ পাশে যতগুলো নাম, ডান পাশে ততগুলো মান নেই। print(len(record)) দিয়ে দেখে নিন ভেতরে আসলে কয়টি আছে।
ValueError: too many values to unpack (expected 2) উল্টো সমস্যা — মান বেশি, নাম কম।
একটিমাত্র মানের টাপল বানিয়েছি, কিন্তু সেটা টাপল হয়নি কমা বাদ পড়েছে। (5) একটি সংখ্যা, (5,) একটি টাপল।
টাপলের ভেতরের লিস্টটা বদলে গেছে টাপল তার নিজের গঠন রক্ষা করে — কোন জিনিসগুলো তার ভেতরে আছে, সেটা বদলানো যায় না। কিন্তু সেই জিনিসগুলোর একটি যদি নিজেই বদলানোর যোগ্য হয়, যেমন একটি লিস্ট, তাহলে সেটির ভেতরটা বদলানো যায়। ([1, 2], 3)-এ প্রথম লিস্টটিতে append করা চলে।
ধাপ ৪ / ৬ — অনুমান
যাচাই করুন
আনপ্যাক করার পর কী ছাপা হবে?
point = (3, 7)
x, y = point
print(y, x)- A7 3
- B3 7
- C(3, 7)
- Dএকটি `ValueError`
একটি টাপলে append করার চেষ্টা। কোন ত্রুটি আসবে, আর কেন সেটিই?
point = (3, 7)
point.append(9)- A`AttributeError` — টাপল বদলানো যায় না, তাই বদলানোর মেথডগুলো তার নেই-ই
- B`TypeError` — টাপলে `append` করা যায় না
- Cকিছুই হয় না, টাপলটি অপরিবর্তিত থাকে
- D`ValueError`
দুটি লাইনের পার্থক্য কেবল একটি কমা। type() কী বলবে?
one = (5)
really = (5,)
print(type(one))
print(type(really))- A<class 'int'> <class 'tuple'>
- B<class 'tuple'> <class 'tuple'>
- C<class 'int'> <class 'int'>
- D<class 'tuple'> <class 'int'>
উত্তর দিতে অ্যাকাউন্ট লাগবে
উত্তর মিলিয়ে দেখতে সাইন ইন করুন
প্রশ্নগুলো উপরে আছে, আর মাথায় মাথায় উত্তর ভেবে নেওয়াই আসল কাজ। সঠিক উত্তর, ব্যাখ্যা আর তিন ধাপের ইঙ্গিত দেখতে সাইন ইন করুন।
নিজে করুন
contacts.py নামে একটি ফাইল লিখুন, যেখানে অন্তত পাঁচজনের একটি লিস্ট থাকবে, আর প্রত্যেকে একটি টাপল — নাম, বয়স আর পছন্দের একটি বিষয়।
তারপর:
for name, age, subject in contacts:দিয়ে সবাইকে সাজানো কলামে ছাপান- সবচেয়ে বয়স্ক ব্যক্তিকে খুঁজে বের করে, আনপ্যাক করে, একটি বাক্যে ছাপান
- শুধু নামগুলোর একটি লিস্ট বানান, আর
joinদিয়ে এক লাইনে ছাপান - গড় বয়স ছাপান
- দুটি ভেরিয়েবলের মান এক লাইনে অদলবদল করে দেখান
তারপর ইচ্ছে করে তিনবার ভাঙুন, আর প্রতিটি বার্তা পড়ুন:
- একটি টাপলের ভেতরের বয়সটা বদলানোর চেষ্টা করুন
- একটি টাপলে
appendকরার চেষ্টা করুন - তিনটি মানের একটি টাপলকে দুটি নামে আনপ্যাক করার চেষ্টা করুন
তিনটি আলাদা ত্রুটির নাম আসবে — TypeError, AttributeError, ValueError। কোনটা কেন, সেটা নিজেকে বুঝিয়ে বলতে পারলে টাপল আপনার আয়ত্তে এসে গেছে।
ধাপ ৬ / ৬
কঠিন করা — অধ্যায়ের কুইজ
সহজ থেকে কঠিন — দশটি প্রশ্ন, শেষেরগুলো ইচ্ছে করেই কঠিন।
সাইন ইন করে কুইজ দিন