Skip to main content

পাইথনে জেনারেটর ও তার খুঁটিনাটি বিষয়

এখানে আমরা দেখব যে পাইথনে জেনারেটর বিষয়টা কি । আমরা কিভাবে জেনারেটর বানাতে পারি । জেনারেটর এক্সপ্রেশন কি ? আমাদের কেন ও কি অবস্থায় জেনারেটর ব্যবহার করা দরকার । তো শুরু করা যাক ।

জেনারেটর কি ?

পাইথনে iterator তৈরি করার সবচেয়ে সহজ উপয় হল জেনারেটর । সাধারণ ভাবে বলতে গেলে জেনারেটর একটা ফাংশন যেটা একটা iterator অবজেক্ট রিটার্ন করে । যেটাকে পরে আমরা iterate করতে পারি । এবং যেটা কেবল মাত্র একবারই iterate করা যাবে ।

এখন প্রশ্ন হল এই জেনারেটর কিভাবে বানানো যায় ?

জেনারেটর বানানো খুব সহজ । আমরা সাধারণ ফাংশন যেভাবে লিখি ঠিক সেভাবেই আমরা জেনারেটর বানাতে পারি । কিন্তু এখানে return স্টেটমেন্টের পরিবর্তে yield স্টেটমেন্ট থাকবে । যদি কোন একটা ফাংশনে অন্তত একটা yield স্টেটমেন্ট থাকে তবে সেটা কে আমরা জেনারেটর বলতে পারি । তবে একটা জেনারেটরে একাধিক yield স্টেটমেন্ট থাকতে পারে ।

yield এবং return দুইটাই ফাংশন থেকে কোন ভেলু রিটার্ন করে কিন্তু দুইটার মধ্যে পার্থক্য হল return স্টেটমেন্ট একটা ফাংশন কে পুরাপুরি terminate করে ফেলে । কিন্তু yield ফাংশন কে terminate না করে ফাংশনকে pauses করে রাখে + ফাংশনের বর্তমান অবস্থাও সেভ করে রাখে এবং পরবর্তীতে ফাংশনের আগের অবস্থা থেকেই কাজ শুরু করে ।

কি জটিল মনে হচ্ছে ? একটা কোড দেখি তাহলে বিষয়টা সহজ হয়ে যাবে । মনে করি আমাদের my_generator() নামে একটা ফাংশন আছে যেটার মধ্যে একাধিক yield স্টেটমেন্ট আছে ।
next(a) কল করার পরে দেখা যাচ্ছে যে আমাদের পুরা ফাংশন কিন্তু কল হয় নি । 6 নং লাইনে এসে থেমে আছে । 6 নং লাইনের আগেই কাজ কিন্তু সে ঠিকই করে ফেলছে । এখন আমরা যদি আবার next(a) দিয়ে কল করি তবে কি ঘটনা ঘটে দেখি ।
এখানে দেখা যাচ্ছে জা ৮ নং লাইন থেকে ১০ নং লাইন পর্যন্ত কাজ হয়েছে । এবং n পরিবর্তিত মান কে সে মনে রেখেছে । ফলে n = 1 এর সাথে 1 যোগ করে নতুন মান ২ রিটার্ন করেছে । এখন আমরা যদি আবার next(a) কল করি তবে সে একই কাজ করবে ।
সে কিন্তু n = 2 এর সাথে ১ যোগ করে ৩ রিটার্ন করেছে । আচ্ছা এখন আমরা যদি আবার next(a) কে কল করি তবে কি ঘটনা ঘটবে ? দেখা যাক রান করে দেখি কি ঘটে ।
Traceback এ দেখে যাচ্ছে যে StopIteration নামে একটা exception খাইছে । এর কারণ আমারা যে generator বানিয়েছি সেটা তো ৩ টা জিনিসই রিটার্ন করে । তো সেখান থেকে আমি কখনই ৪ টা জিনিস আশা করতে পারি না ।
উপরের ঘটনাগুলির সারাংশ এইরকম হতে পারে
  1. প্রত্যেক কল এ ভেরিয়েবল n এর মান মনে রাখা হয় ।
  2. সাধারণ ফাংশনের মত ভেলু রিটার্ন করার পরে লোকাল ভেরিয়েবল ধ্বংস হয়ে যায় না ।
  3. Generator অবজেক্ট কেবল একবারই iterate করা যায়
  4.  নতুন করে iterate করা জন্য আমাদের কে a = my_generator() আবার কল করতে হবে ।

Python Generators কে লুপের মাধ্যমে iterate করা :


Python Generator Expression:

এটা হল ফাংশন ক্রিয়েট না করেই জেনারেটর অবজেক্ট ক্রিয়েট করা । আমাদের জেনারেটর ফাংশন যদি খুব ছোট হয় তবে সেটা ইমপ্লিমেন্ট করা জন্য আলাদা করে ফাংশন ডিফাইন করার দরকার নাই । ল্যামডা ফাংশন যেমন anonymous function ক্রিয়েট করতে পারে । ঠিক তেমনি ভাবে generator expression, anonymous generator ফাংশন ক্রিয়েট করতে পারে ।

Generator expression এর সিনট্যাক্স list comprehension এর মতই শুধু পার্থক্য হল এখানে square brackts এর পরিবর্তে round parentheses ব্যবহার করা হয় । কিছু উদাহরণ দেখা যাক ।

কেন আমরা Generator ব্যবহার করব ?

অনেকের মনে হতে পারে যে জেনারেটরের কাজ তো সাধারণ ফাংশন ও লিস্ট কম্প্রিহেন্সনের মাধ্যমেই করা যায় তবে এটা দরকার টা কি ? এর বেশ কিছু সুবিধা আছে তার মধ্যে অন্যতম

মেমরি খরচ অনেক কমায়ে দেয় :

প্রশ্ন হতে পারে যে মেমরি খরচ কিভাবে কমায়ে দেয় ? মনে করেন আমাদের একটা ফাংশন আছে যেটা 2GB ইমেজ ফাইল রিড করে একটা লিস্ট ভেরিয়েবলে স্টোর করে রাখে সব ফাইল রিড করা শেষ হলে লিস্ট টি রিটার্ন করে দেয় । আমাদের ফাংশন টা যদি সাধারণ ফাংশন হয় তবে এটা পুরা 2GB ইমেজের ডাটা কে মেমরিতে তে লোড করে রাখবে যতক্ষণ না সেটা ফাইনাল লিস্ট কে return করে ।

কিন্তু আমরা যদি জেনারেটর ব্যবহার করি তবে আমাদের কে পুরা 2GB ইমাজের ডাটা কে মেমরিতে লোড করতে হচ্ছে না । কারণ আমরা দেখেছি যে জেনারেটর একক সময়ে কেবল একটাই আইটেম রিটার্ন করে ।

অসীম একটা Stream কে রিপ্রেজেন্ট করা যায়:

আপনার যদি অসীম সংখ্যক ডাটা থাকে তবে আপনি খুব সহজেই জেনারেটর দিয়ে সেটা কে রিপ্রেজেন্ট করতে পারবেন । কি বিশ্বাস হচ্ছে না ? আমরও অবশ্য শুরুতে বিশ্বাস হয় নি । কিন্তু এখন হয় । একটা উদাহরণ দেই তাহলেই বিশ্বাস হয়ে যাবে ।

Fibonacci numbers এর সাথে আমরা অনেকেই পরিচিত । তো আমরা Fibonacci number এর অসীম stream generate করার চেষ্টা করি ।
বিশাল বড় দুইটা Fibonacci সংখ্যা দিয়ে দিছে । কি ভয়ঙ্কর সুন্দর ও সাঙ্ঘাতিক ব্যাপার । আপনার মেশিন যতটুকু লোড নিতে পারবে সেটা উপর ভিত্তি করে আপনি 10000, 10002 এইটা দুইটা মান ছোট ও বড় বসাতে পারেন । আমার মেশিনে এর থেকে বড় সংখ্যা দিলে মেশিনের অবস্থা খারাপ হয়ে যাবে ।

আপনার সিস্টেম সবচেয়ে বড় কি সংখ্যা দেয়া যেতে পারে তার জন্য আপনই sys.maxsize দিয়ে সাইজ দেখে নিতে পারেন ।

এই দুইটা বাদেও generator এর আরও কিছু আপ্লিকেশন আছে । সেগুলো জানার জন্য আপনি গুগল করতে পারেন । আজকে এ পর্যন্তই ।

মুল লেখা: https://github.com/menon92/Python-Learning/blob/master/python_generator_by_example.ipynb

Comments

Popular posts from this blog

Operator Overloading Vs priority_queue in C++

priority_queue ডিফল্ট ভাবে বড় ডাটা কে টপে নিয়ে আশে । আমরা যদি < অপারেটর ওভারলোড করি তবে আমাদের মাথায় রাখতে হবে যে STL priority_queue হল ম্যাক্স priority_queue যার অর্থ ম্যাক্স উপদান কে সবার প্রথমে নিয়ে আসবে । এটা কে min priority_queue এ নিয়ে আসতে হলে return a.age < b.age;  এই লাইন কে , return a.age > b.age; এই লাইন দিয়ে পরিবর্তন করতে হবে । কোড : Output : 10 9 8 7 6 5 4 3 2 1 এখন আমরা যদি আউটপুট কে 1 2 3 4 5 6 7 8 9 10 দেখাতে চাই তবে ১২ নং লাইন পরিবর্তন করে লিখতে হবে return a.age > b.age; ধন্যবাদ :)
  Good becomes great, bad becomes worse. A strong man who has known power all his life can lose respect for that power, but a weak man knows the value of strength and knows compression

পাইথনে Yield কিভাবে কাজ করে ?

Yield কি সেটা বোঝার জন্য Generator বোঝা লাগবে । আবার Generator কি সেটা বোঝার জন্য Iterables বুঝতে হবে । কি প্রথমেই মাথা ঘুরে গেল ? আচ্ছা মাথা ঘুরলে ঘুরতে দেন :D  আমরা শুরু করে দেই  । Iterables কি ? আমরা যখন কোন লিস্ট ক্রিয়েট করি । আমরা লিস্টের আইটেম গুলি একটা একটা করে রিড করতে পারি । এটাকেই বলা হচ্ছে iteration code: এখানে my_list হল iterable . যখন আমরা list comprehension ব্যবহার করে কোন লিস্ট ক্রিয়েট করি সেটাও একটা iterable । code : Python এ যেসব জিনিস iterable যেমন: টাপল, লিস্ট, ফাইল, স্ট্রিং, .... ইত্যাদি কে আমরা for .... in ...: দিয়ে রিড করতে পারবো । ডাটা খুব সহজেই রিড করার জন্য এইটা খুব কাজে দেয় । কিন্তু এর একটা সমস্যা আছে । সেটা হল । এইটা সব সময় লিস্টের আইটেম গুলিকে মেমরি তে ষ্টোর করে রাখে । এখন আমাদের সবসময় মেমরি তে লিস্ট আইটেম গুলি সেভ করে নাও রাখা লাগতে পারে । তো এইটা আমরা কি ভাবে সমাধান করবো ? Generators কি ? Generators গুলো হল  একধরনের iterators । কিন্তু আমরা কেবল একবারই generator এ iterate করতে পারি । এর কারণ হল generator সব ভেলু কে মেমরি তে ষ্টোর...