কেস স্টাডি: Python-এর ডিজাইন সিদ্ধান্ত
এই পাঠে যা শিখবেন
- Python-এর ডায়নামিক টাইপিং ও ডাক টাইপিং দর্শন, এবং কেন এটি লেখার সহজতাকে অগ্রাধিকার দেয়
- Python বাস্তবে কীভাবে M12/L54-এর রেফারেন্স-সাইকেল সমস্যা সমাধান করে
- Python কীভাবে একই ভাষায় ইম্পারেটিভ, OOP ও ফাংশনাল স্টাইল একসাথে সমর্থন করে
- LEGB স্কোপিং নিয়ম — M8/L38-এর স্ট্যাটিক স্কোপিং-এর একটি বাস্তব, দৈনন্দিন উদাহরণ
১ · ডায়নামিক টাইপিং ও ডাক টাইপিং
Python ডায়নামিক টাইপডM7/L32-এ বিস্তারিত — একটি ভ্যারিয়েবলের টাইপ কম্পাইল-টাইমে নয়, রানটাইমে তার বর্তমান মানের উপর ভিত্তি করে নির্ধারিত হয়। — কোনো ভ্যারিয়েবল ঘোষণার সময় টাইপ লিখতে হয় না। এই সিদ্ধান্ত থেকেই সরাসরি জন্ম নেয় Python-এর সিগনেচার দর্শন: ডাক টাইপিংDuck Typing"যদি এটি হাঁসের মতো হাঁটে ও হাঁসের মতো ডাকে, তাহলে এটিকে হাঁস ধরে নাও" — একটি অবজেক্টের কোনো অপারেশনের জন্য উপযুক্ততা নির্ধারিত হয় সে রানটাইমে প্রয়োজনীয় মেথড/অপারেশন সাপোর্ট করে কিনা তা দিয়ে, তার ঘোষিত টাইপ দিয়ে নয়। — ডায়নামিক টাইপিং (M7/L32)-এর একটি সরাসরি, বাস্তব ফলাফল, যা লেখার সহজতা/নমনীয়তাকে (M1/L04-এর writability) অগ্রাধিকার দেয়, কিছুটা compile-time এরর-ধরার ক্ষমতার বিনিময়ে।
২ · গার্বেজ কালেকশন — L54-এর সমস্যার প্রকৃত সমাধান
M12/L54-এ আমরা দেখেছি বিশুদ্ধ রেফারেন্স কাউন্টিং কখনোই একটি রেফারেন্স সাইকেল রিক্লেইম করতে পারে না। Python বাস্তবে এই সমস্যা রেফারেন্স কাউন্টিং-কে প্রাইমারি কৌশল হিসেবে রেখে, তার সাথে একটি সম্পূরক সাইকেল-ডিটেক্টর যোগ করে সমাধান করে — এই সাইকেল ডিটেক্টর পর্যায়ক্রমে চলে, ঠিক সেই ধরনের পারস্পরিক-রেফারেন্সিং গ্রুপ খুঁজে বের করে যা L54-এর কোড সেলে হাতে-কলমে তৈরি করা হয়েছিল, এবং সেগুলোকে বিশেষভাবে রিক্লেইম করে।
৩ · মাল্টি-প্যারাডাইম প্রকৃতি
M2/L10-এর মাল্টি-প্যারাডাইম থিমের একটি বাস্তব, প্রত্যক্ষ উদাহরণ — Python একই সাথে ইম্পারেটিভ
(M2/L06 — সাধারণ লুপ ও স্টেট মিউটেশন), OOP (M2/L07 — class), এবং
ফাংশনাল (M2/L08 — lambda, map/filter, ফার্স্ট-ক্লাস
ফাংশন) স্টাইল স্বচ্ছন্দে সমর্থন করে — প্রোগ্রামার সমস্যার প্রকৃতি অনুযায়ী স্টাইল বেছে নিতে পারে।
৪ · LEGB স্কোপিং
Python-এর স্কোপ রেজোলিউশন নিয়ম — LEGB (Local, Enclosing, Global, Built-in) — একটি নাম খুঁজতে প্রথমে স্থানীয় স্কোপ, তারপর ঘিরে-থাকা (enclosing) ফাংশন স্কোপ, তারপর গ্লোবাল স্কোপ, তারপর built-in স্কোপ দেখে — এটি M8/L38-এর স্ট্যাটিক (লেক্সিক্যাল) স্কোপিং-এর "বাইরের দিকে খুঁজে যাওয়া" নীতিরই একটি নির্দিষ্ট, নামযুক্ত বাস্তব রূপ — প্রতিদিন Python লেখা প্রোগ্রামাররা এই নিয়মের উপর নির্ভর করেন, প্রায়ই এই কোর্সের পরিভাষা না জেনেই।
Python-এর প্রায় প্রতিটি প্রধান ডিজাইন সিদ্ধান্ত এই কোর্সের কোনো না কোনো নির্দিষ্ট মডিউলের একটি বাস্তব উদাহরণ — এটাই এই কেস স্টাডির মূল উদ্দেশ্য: তত্ত্ব শুধু বিমূর্ত ধারণা নয়, বাস্তব ভাষার প্রতিটি "অনুভূতি"-র (feel) পেছনে একটি সুনির্দিষ্ট, নামযুক্ত ডিজাইন সিদ্ধান্ত আছে।
৫ · বাস্তবায়ন — একটি বাস্তব ডাক টাইপিং ডেমো
নিচের কোড সেলে দুটো সম্পূর্ণ অসম্পর্কিত ক্লাস — কোনো কমন বেস ক্লাস নেই, কোনো টাইপ ঘোষণা নেই — শুধু কাকতালীয়ভাবে
উভয়েরই .quack() মেথড আছে। make_it_quack ফাংশন কখনো তাদের টাইপ পরীক্ষা করে না, শুধু
কল করার চেষ্টা করে — এটাই ডাক টাইপিং হাতেকলমে।
class Duck:
def quack(self):
return "কোয়াক! আমি একটি হাঁস।"
class ToyDuck:
"""সম্পূর্ণ অসম্পর্কিত ক্লাস -- Duck-এর সাথে কোনো বেস ক্লাস শেয়ার করে না,
কোনো টাইপ ঘোষণাও নেই -- শুধু কাকতালীয়ভাবে একই .quack() মেথড আছে।"""
def quack(self):
return "স্কুইক-কোয়াক! আমি একটি খেলনা হাঁস।"
class Person:
"""এই ক্লাসের quack() নেই -- ডাক টাইপিং এটিকে রিজেক্ট করবে।"""
def speak(self):
return "আমি একজন মানুষ, আমি quack করতে পারি না।"
def make_it_quack(thing):
"""ডাক টাইপিং: thing-এর ঘোষিত টাইপ কী তা কখনো পরীক্ষা করা হয় না --
শুধু thing.quack() আছে কিনা এবং কল করা যায় কিনা, তাই গুরুত্বপূর্ণ।"""
return thing.quack()
print("ডাক টাইপিং ডেমো:")
for obj in [Duck(), ToyDuck()]:
print(f" {type(obj).__name__}.quack() -> {make_it_quack(obj)}")
print("\nPerson-এর জন্য চেষ্টা করলে (quack() নেই):")
try:
make_it_quack(Person())
except AttributeError as e:
print(" AttributeError সঠিকভাবে ধরা পড়ল:", e)
print("\n\nPython-এর ডিজাইন সিদ্ধান্ত <-> এই কোর্সের পাঠ:")
design_choices = {
"ডায়নামিক টাইপিং + ডাক টাইপিং": {
"কোর্স রেফারেন্স": "M7/L32",
"উদাহরণ": "উপরের make_it_quack() -- কোনো টাইপ ঘোষণা ছাড়াই কাজ করে",
},
"প্রাইমারি GC = রেফারেন্স কাউন্টিং + সাইকেল ডিটেক্টর": {
"কোর্স রেফারেন্স": "M12/L54",
"উদাহরণ": "CPython-এর gc মডিউল L54-এর সাইকেল সমস্যার বাস্তব সমাধান",
},
"মাল্টি-প্যারাডাইম": {
"কোর্স রেফারেন্স": "M2/L10",
"উদাহরণ": "class + lambda/map/filter + সাধারণ ইম্পারেটিভ কোড, সব একসাথে",
},
"LEGB স্কোপিং": {
"কোর্স রেফারেন্স": "M8/L38",
"উদাহরণ": "Local -> Enclosing -> Global -> Built-in, স্ট্যাটিক স্কোপিং-এরই একটি নামকরণ",
},
}
for choice, info in design_choices.items():
print(f"\n {choice}")
print(f" কোর্স রেফারেন্স : {info['কোর্স রেফারেন্স']}")
print(f" উদাহরণ : {info['উদাহরণ']}")
make_it_quack ফাংশনটি Duck বা ToyDuck কোনোটির টাইপই
কখনো পরীক্ষা করেনি (কোনো isinstance() চেক নেই), তবুও উভয়ের জন্যই সঠিকভাবে কাজ করেছে। কিন্তু
Person-এর জন্য চেষ্টা করলে AttributeError আসে — কারণ রানটাইমে দেখা যায় প্রয়োজনীয়
.quack() মেথডই নেই। এটাই ডাক টাইপিং-এর মূল কথা — "টাইপ কী" নয়, "কী করতে পারে" গুরুত্বপূর্ণ,
এবং সেই যাচাই রানটাইমেই ঘটে, কম্পাইল-টাইমে নয়।
Python-এর "অনুভূতি" — নমনীয়, লেখা সহজ, কিন্তু কম compile-time গ্যারান্টি — এই কোর্সের নির্দিষ্ট ডিজাইন সিদ্ধান্তগুলোর প্রত্যক্ষ ফল: ডায়নামিক টাইপিং (M7), রেফারেন্স-কাউন্টিং-ভিত্তিক GC (M12), মাল্টি-প্যারাডাইম নমনীয়তা (M2), এবং সহজবোধ্য LEGB স্কোপিং (M8) — কোনোটিই কাকতালীয় নয়, প্রতিটিই একটি সচেতন ট্রেড-অফ।
ভাবনার প্রশ্ন
প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।
প্র ০১ ডাক টাইপিং-এর সুবিধা হলো নমনীয়তা। এর কী মূল্য দিতে হয় — কোন সমস্যাটি ডাক টাইপিং কম্পাইল-টাইমে ধরতে পারে না যা স্ট্যাটিক টাইপিং পারে?
একটি অবজেক্টে প্রয়োজনীয় মেথড নেই — এই ভুলটি ডাক টাইপিং-এ কেবল রানটাইমে, যখন সেই নির্দিষ্ট কোড পাথ আসলে
এক্সিকিউট হয়, তখনই ধরা পড়ে (উপরের কোড সেলে Person-এর AttributeError ঠিক এভাবেই
এসেছে)। স্ট্যাটিক টাইপিং-এ (M7/L32) এই একই ভুল প্রোগ্রাম রান করার আগেই, কম্পাইল-টাইমেই ধরা পড়ত — এটাই M1/L04-এর
writability বনাম reliability ট্রেড-অফের একটি বাস্তব উদাহরণ।
প্র ০২ Python যদি শুধু রেফারেন্স কাউন্টিং ব্যবহার করত, সাইকেল ডিটেক্টর ছাড়া, তাহলে দীর্ঘ সময় ধরে চলা একটি প্রোগ্রামে কী সমস্যা হতে পারত?
M12/L54-এর কোড সেলে দেখানো সাইকেল-সমস্যাটি ধীরে ধীরে জমতে থাকত — প্রতিটি নতুন তৈরি হওয়া, কিন্তু আর reachable না হওয়া অবজেক্ট-সাইকেল স্থায়ীভাবে মেমরিতে আটকে থাকত, কারণ তাদের ref_count কখনো শূন্যে পৌঁছাত না। দীর্ঘ সময় ধরে চলা একটি প্রোগ্রামে (যেমন একটি ওয়েব সার্ভার) এটি ধীরে ধীরে মেমরি ব্যবহার বাড়িয়ে দিত — কার্যত একটি মেমরি লিক তৈরি করত, যদিও প্রোগ্রামার কোনো ম্যানুয়াল মেমরি ভুল করেনি।
প্র ০৩ LEGB-এর "E" (Enclosing) অংশটি M8-এর কোন নির্দিষ্ট পাঠের সাথে সবচেয়ে সরাসরি সম্পর্কিত, এবং কেন?
M8/L40-এর ক্লোজার ও লেক্সিক্যাল এনভায়রনমেন্ট-এর সাথে সরাসরি সম্পর্কিত। "Enclosing" স্কোপ মানে একটি ভেতরের (nested) ফাংশনের বাইরের ফাংশনের স্কোপ — একটি ক্লোজার ঠিক এই enclosing স্কোপের ভ্যারিয়েবলগুলো "মনে রেখে" দেয়, এমনকি বাইরের ফাংশন রিটার্ন করে যাওয়ার পরেও। LEGB-এর E ধাপটি তাই ক্লোজার বাস্তবায়নের স্কোপ-লুকআপ নিয়মেরই একটি নাম।
অনুশীলন
-
চিন্তা করুন: উপরের কোড সেলে যদি আরেকটি ক্লাস
Airplaneতৈরি করা হয় যার একটি.quack()মেথড আছে যা"vroom!"রিটার্ন করে, তাহলেmake_it_quack(Airplane())কী করবে?এটি সফলভাবে
"vroom!"রিটার্ন করবে, কোনো এরর ছাড়াই — এটাই ডাক টাইপিং-এর সবচেয়ে চরম উদাহরণ: একটি "প্লেন" আক্ষরিক অর্থে "হাঁসের মতো ডাকতে" পারবে যদি তার একটি.quack()মেথড থাকে, তা যত অস্বাভাবিকই শোনাক না কেন। এটি দেখায় ডাক টাইপিং সম্পূর্ণভাবে অন্ধ concept/semantic সম্পর্কের প্রতি — শুধু মেথডের উপস্থিতি ও কলযোগ্যতাই গুরুত্বপূর্ণ, বাস্তব "অর্থ" নয়। -
পরীক্ষা করুন: উপরের কোড সেলে
make_it_quack-এর ভেতরেPerson-এর জন্য try/except বাদ দিয়ে সরাসরি কল করলে কী এরর মেসেজ আসে তা লক্ষ্য করে দেখুন।AttributeError: 'Person' object has no attribute 'quack'ধরনের একটি মেসেজ আসবে — Python রানটাইমে অবজেক্টের অ্যাট্রিবিউট/মেথড টেবিল দেখে এবংquackনামে কিছু না পেয়ে এই এরর তোলে। এই এরর মেসেজটিই প্রমাণ করে টাইপ-চেকিং এখানে সম্পূর্ণ রানটাইম ঘটনা — কোনো আলাদা কম্পাইল-টাইম টাইপ-চেকিং ধাপ (M6/L30) নেই যা আগেভাগে এই সমস্যা ধরতে পারত।
আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ
- কোর্সের সম্পূর্ণ সিলেবাস দেখুন ৫৮টি পাঠ পরের পাঠে সম্পূর্ণ ভিন্ন দর্শনের একটি ভাষা — Rust-এর ওনারশিপ ও বরো চেকার, GC ছাড়াই মেমরি সেফটি।
- রানটাইম এনভায়রনমেন্ট ও গার্বেজ কালেকশন (L54) M12 · আগের পাঠ রেফারেন্স কাউন্টিং ও সাইকেল সমস্যার তাত্ত্বিক ভিত্তি — যা এই পাঠে Python-এর বাস্তব সমাধানে প্রয়োগ করা হয়েছে।
- কেস স্টাডি: Rust-এর ওনারশিপ ও বরো চেকার (L56) পরের পাঠ GC ছাড়াই মেমরি সেফটি অর্জনের সম্পূর্ণ ভিন্ন একটি পথ — কম্পাইল-টাইম ওনারশিপ চেকিং।