টাপল আর আনপ্যাকিং
বদলানো যায় না এমন লিস্ট — কোথায় সেটাই দরকার, আনপ্যাকিং দিয়ে ইনডেক্সের বদলে নাম ব্যবহার, এক লাইনে অদলবদল, আর (5) বনাম (5,)-এর ফাঁদ।
কীভাবে শিখতে চান?
যে সমস্যাটা আমরা সমাধান করছি
তিন দিনের আবহাওয়ার হিসাব রাখতে হবে — প্রতিদিনের দিন, তাপমাত্রা আর আর্দ্রতা।
লিস্ট দিয়ে করা যায়: ["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 মানে “এই অবজেক্টে এই নামে কিছু নেই”। টাপল বদলানো যায় না, তাই টাপলের append নামে কোনো মেথডই নেই। পাইথন point.append খুঁজতেই গিয়ে থেমে যায়, 9 যোগ করার চেষ্টা পর্যন্ত পৌঁছায়ই না। আগের উদাহরণের সাথে পার্থক্যটা এখানে: point[0] = 5 এমন একটা কাজ চেয়েছিল যা টাপল করতে দেয় না, তাই TypeError; আর এখানে মেথডটাই নেই, তাই AttributeError।
কেন এটা সুবিধা, বাধা নয়
প্রথমে মনে হয় টাপল হলো কম ক্ষমতার লিস্ট। উল্টো করে ভাবুন: যে জিনিসটা বদলানোর কথা নয়, তাকে বদলানো যায় না এমন পাত্রে রাখলে ভুলটা ঘটার আগেই আটকে যায়।
একটি স্থানাঙ্ক (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)- A3 7
- B(3, 7)
- Cএকটি `ValueError`
- D7 3
একটি টাপলে append করার চেষ্টা। কোন এরর আসবে, আর কেন সেটিই?
point = (3, 7)
point.append(9)- A`ValueError`
- Bকিছুই হয় না, টাপলটি অপরিবর্তিত থাকে
- C`AttributeError` — টাপল বদলানো যায় না, তাই বদলানোর মেথডগুলো তার নেই-ই
- D`TypeError` — টাপলে `append` করা যায় না
দুটি লাইনের পার্থক্য কেবল একটি কমা। type() কী বলবে?
one = (5)
really = (5,)
print(type(one))
print(type(really))- A<class 'int'> <class 'int'>
- B<class 'tuple'> <class 'tuple'>
- C<class 'int'> <class 'tuple'>
- D<class 'tuple'> <class 'int'>
উত্তর দিতে অ্যাকাউন্ট লাগবে
উত্তর মিলিয়ে দেখতে সাইন ইন করুন
প্রশ্নগুলো উপরে আছে, আর মাথায় মাথায় উত্তর ভেবে নেওয়াই আসল কাজ। সঠিক উত্তর, ব্যাখ্যা আর তিন ধাপের ইঙ্গিত দেখতে সাইন ইন করুন।
নিজে করুন
contacts.py নামে একটি ফাইল লিখুন, যেখানে অন্তত পাঁচজনের একটি লিস্ট থাকবে, আর প্রত্যেকে একটি টাপল — নাম, বয়স আর পছন্দের একটি বিষয়।
তারপর:
for name, age, subject in contacts:দিয়ে সবাইকে সাজানো কলামে ছাপান- সবচেয়ে বয়স্ক ব্যক্তিকে খুঁজে বের করে, আনপ্যাক করে, একটি বাক্যে ছাপান
- শুধু নামগুলোর একটি লিস্ট বানান, আর
joinদিয়ে এক লাইনে ছাপান - গড় বয়স ছাপান
- দুটি ভেরিয়েবলের মান এক লাইনে অদলবদল করে দেখান
তারপর ইচ্ছে করে তিনবার ভাঙুন, আর প্রতিটি বার্তা পড়ুন:
- একটি টাপলের ভেতরের বয়সটা বদলানোর চেষ্টা করুন
- একটি টাপলে
appendকরার চেষ্টা করুন - তিনটি মানের একটি টাপলকে দুটি নামে আনপ্যাক করার চেষ্টা করুন
তিনটি আলাদা এররের নাম আসবে — TypeError, AttributeError, ValueError। কোনটা কেন, সেটা নিজেকে বুঝিয়ে বলতে পারলে টাপল আপনার আয়ত্তে এসে গেছে।
ধাপ ৬ / ৬
কঠিন করা — অধ্যায়ের কুইজ
সহজ থেকে কঠিন — দশটি প্রশ্ন, শেষেরগুলো ইচ্ছে করেই কঠিন।
সাইন ইন করে কুইজ দিন