ডেকোরেটর এবং ক্লোজার (Decorators & Closures)
ফাংশন হলো ফার্স্ট-ক্লাস সিটিজেন বা প্রথম শ্রেণীর নাগরিক (Functions Are First-Class Citizens)
পাইথনে ফাংশনগুলো অন্য যেকোনো ভ্যালুর মতোই কেবল একেকটি অবজেক্ট (object)। আপনি এগুলোকে ভ্যারিয়েবলে সংরক্ষণ করে রাখতে পারেন, আর্গুমেন্ট হিসেবে পাস করতে পারেন এবং অন্য ফাংশন থেকে রিটার্নও করতে পারেন। এটি প্রথমে অদ্ভুত লাগতে পারে, তবে এটিই এই লেসনের সবকিছুর মূল ভিত্তি।
এভাবে চিন্তা করুন: একটি ফাংশন হলো একটি রেসিপি কার্ডের (recipe card) মতো। আপনি চাইলে কার্ডটি অন্য কাউকে দিতে পারেন (আর্গুমেন্ট হিসেবে পাস করা), এর ফটোকপি করতে পারেন (অন্য ভ্যারিয়েবলে অ্যাসাইন করা), বা এমনকি একটি ফ্যাক্টরির ভেতরে নতুন রেসিপি কার্ড তৈরি করতে পারেন (একটি ফাংশন থেকে অন্য ফাংশন রিটার্ন করা)।
অবজেক্ট হিসেবে ফাংশন (Functions as Objects)
ক্লোজার — যে ফাংশনগুলো মনে রাখে (Closures — Functions That Remember)
ক্লোজার (closure) হলো এমন একটি ফাংশন যা যেখানে তৈরি হয়েছিল, সেই জায়গার ভ্যারিয়েবলগুলোকে "মনে রাখে," এমনকি সেই জায়গাটির আর কোনো অস্তিত্ব না থাকলেও। এটি অনেকটা স্নোগ্লোবের (snowglobe) মতো — যার ভেতরের ছোট্ট জগতটি বরফে জমে আছে, কিন্তু আপনি এখনও বাইরে থেকে সেটিকে দেখতে পাচ্ছেন।
ক্লোজারের তৈরি তখনই হয় যখন একটি ভেতরের ফাংশন, তার বাইরের ফাংশনের স্কোপ (scope) থেকে একটি ভ্যারিয়েবল রেফারেন্স (reference) হিসেবে গ্রহণ করে। ভেতরের ফাংশনটি সেই ভ্যারিয়েবলগুলোকে ঘিরে ধরে বা ক্লোজ ওভার (closes over) করে এবং সেগুলোকে নিজের সাথে বহন করে নিয়ে যায়।
ক্লোজারের ব্যবহার (Closures in Action)
ডেকোরেটর — মূল আকর্ষণ (Decorators — The Main Event)
ডেকোরেটর (decorator) হলো এমন ফাংশন যা অন্য একটি ফাংশন গ্রহণ করে, এতে কিছু বাড়তি কাজ বা আচরণ যোগ করে এবং একটি নতুন ও উন্নত করা ফাংশন রিটার্ন করে। এটি অনেকটা কোনো উপহারকে গিফট-র্যাপিং বা মোড়ক দিয়ে পেঁচানোর মতো — ভেতরের উপহারটি একই থাকে, তবে মোড়কটি এতে বাড়তি কিছু যোগ করে (যেমন একটি ফিতা, ট্যাগ, বা চুমকি)।
@decorator এর লেখার নিয়মটি কেবলই একটি সিনট্যাক্টিক সুগার (syntactic sugar)। কোনো ফাংশনের সংজ্ঞার ওপরে @my_decorator লেখা আর my_func = my_decorator(my_func) লেখা, দুটো আসলে একদম একই জিনিস।
একটি ডেকোরেটর তৈরি করা (Building a Decorator)
বাস্তব জীবনের ডেকোরেটর প্যাটার্নগুলো (Real-World Decorator Patterns)
প্রফেশনাল পাইথন কোডে ডেকোরেটরের দেখা সব জায়গায় মিলে। নিচে এর কিছু সাধারণ ব্যবহার বা প্যাটার্ন দেওয়া হলো:
- লগিং (Logging) — ফাংশনগুলো কখন এবং কী কী আর্গুমেন্ট নিয়ে কল করা হলো তা নজরে বা ট্র্যাকে (track) রাখা
- অ্যাউথেন্টিকেশন (Authentication) — কোনো ব্যবহারকারীর ফাংশনটিকে কল করার অনুমতি আছে কি না তা যাচাই করা
- ক্যাশিং/মেমোইজেশন (Caching/Memoization) — একই কাজ বা হিসাব পুনরায় করা এড়াতে রেসাল্ট বা ফলাফল মনে রাখা
- রিট্রাই লজিক (Retry logic) — কোনো অপারেশন ব্যর্থ হলে স্বয়ংক্রিয়ভাবে আবার বা রিট্রাই (retry) করার চেষ্টা করা
- ভ্যালিডেশন (Validation) — ফাংশন রান করার আগে ইনপুট ঠিক আছে কি না তা যাচাই করা
প্র্যাকটিক্যাল ডেকোরেটরসমূহ (Practical Decorators)
আর্গুমেন্টসহ ডেকোরেটর (Decorators with Arguments)
মাঝেমধ্যে আপনি কোনো ডেকোরেটরকে কনফিগার (configure) করতে চাইতে পারেন — যেমন সেটিকে জানিয়ে দেওয়া যে কতবার রিট্রাই (retry) করতে হবে, বা ঠিক কোন মেসেজটি লগ (log) করতে হবে। এর জন্য আপনার একটি ডেকোরেটর ফ্যাক্টরির (decorator factory) প্রয়োজন হবে: এমন একটি ফাংশন যা আর্গুমেন্ট গ্রহণ করে এবং একটি ডেকোরেটর রিটার্ন করে।
প্যারামিটারাইজড ডেকোরেটর (Parameterized Decorators)
@functools.wraps(func) ব্যবহার করবেন। এটি ছাড়া, ডেকোরেট করা ফাংশনটি তার আসল নাম এবং ডকস্ট্রিং (docstring) হারিয়ে ফেলে, যা ডিবাগিং করাকে এক দুঃস্বপ্নে পরিণত করে দেয়। এক লাইনের এই কোডটি আপনার ঘণ্টার পর ঘণ্টা বিভ্রান্তি বা কনফিউশন দূর করতে সাহায্য করবে।