মেটা প্রোগ্রামিং বলতে কম্পিউটার প্রোগ্রামিংকে বুঝায় যেখানে কম্পিউটার প্রোগ্রাম নিজে নিজে ম্যানিপুলেট করার চেষ্টা করে বা নিজের সম্পর্কে জ্ঞান রাখে। পাইথন ক্লাসের জন্য মেটা প্রোগ্রামিং সাপোর্ট করে মেটাক্লাস নামে একটি নতুন ধরনের ক্লাসের মাধ্যমে।
পাইথনে মেটাক্লাসের মাধ্যমে মেটা-প্রোগ্রামিং হলো ফাংশন এবং ক্লাস তৈরি করা যা কোড মডিফাই, র্যাপ বা জেনারেট করে এক্সিস্টিং কোডকে ম্যানিপুলেট করে।
মেটা-প্রোগ্রামিং-এর মূল বৈশিষ্ট্যগুলো হলো:
- মেটাক্লাস
- ডেকোরেটর
- ক্লাস-ডেকোরেটর
মেটাক্লাস কী
মেটাক্লাসের একটি সংকীর্ণ ডেফিনিশন হতে পারে, একটি ক্লাস যা ক্লাস তৈরি করে। পাইথন একটি অবজেক্ট-ওরিয়েন্টেড ল্যাঙ্গুয়েজ যেখানে সবকিছুই একটি অবজেক্ট এবং ক্লাসগুলোও এক্সসেপশন নয়। class কিওয়ার্ড দিয়ে একটি ক্লাস ডিফাইন করলে, পাইথন আসলে সেটি এক্সিকিউট করে এবং তারপর একটি অবজেক্ট জেনারেট করে। যেহেতু এটি একটি অবজেক্ট, আপনি এটিকে অ্যাসাইন, কপি, অ্যাট্রিবিউট যোগ, ফাংশন প্যারামিটার হিসেবে ব্যবহার, ইত্যাদি করতে পারেন। মেটাক্লাস ব্যবহার করে আমরা ক্লাস জেনারেশনের উপর কন্ট্রোল করতে পারি, যেমন ক্লাসের প্রোপার্টি মডিফাই করা, প্রোপার্টির বৈধতা চেক করা, ইত্যাদি।
পাইথন বিল্ট-ইন মেটাক্লাস
সকল ক্লাসের মেটাক্লাস হলো type
class a: pass print(type(a))
আউটপুট:
উপরের আউটপুট থেকে আমরা দেখতে পাচ্ছি "a"(ক্লাস) type ক্লাসের একটি অবজেক্ট। আমরা এটিকে বলতে পারি "a"(ক্লাস) type ক্লাসের একটি ইন্সট্যান্স। তাই type একটি মেটাক্লাস। তাই পাইথনে, প্রতিটি ক্লাস বিল্ট-ইন মেটাক্লাস type-এর অন্তর্গত।

মেটাক্লাস ব্যবহার করে পাইথন ক্লাস তৈরি করা
উপরের উদাহরণে আমরা দেখেছি, type ডিফল্ট মেটাক্লাস। আমরা এই ডিফল্ট মেটাক্লাস (type) সাহায্যে একটি নতুন ক্লাস তৈরি করতে পারি।
>>> class hello(object): pass
এটিকে ম্যানুয়ালি এইভাবেও তৈরি করা যায়:
>>> hello = type('hello', (), {})
>>> print(hello) # একটি ক্লাস অবজেক্ট রিটার্ন করে
>>> print(hello()) # ক্লাস দিয়ে একটি ইন্সট্যান্স তৈরি করে
<__main__.hello object at 0x05D86830>
Type একটি ডিকশনারি অ্যাক্সেপ্ট করে ক্লাসের অ্যাট্রিবিউট ডিফাইন করতে, তাই
>>> class hello(object):
world = True
উপরের কোড এর সমান:
hello = type('hello', (), {'world': True})
একটি মেটাক্লাস তৈরি করা
তবে কখন একটি মেটাক্লাস তৈরি করব? যখন আমি একটি ক্লাসের সৃষ্টি নিয়ন্ত্রণ করতে চাই, যেমন ক্লাসের প্রোপার্টি ভেরিফাই বা মডিফাই করা।
ক্লাসের ইন্সট্যানসিয়েশন প্রক্রিয়া:
- __new__() কল করে একটি ইন্সট্যান্স তৈরি করুন
- উপরোক্ত তৈরি ইন্সট্যান্সটি ইনিশিয়ালাইজ করতে __init__() কল করুন
তাই যখন আমরা একটি কাস্টম মেটাক্লাস তৈরি করি, আমরা আসলে পেরেন্ট ক্লাসের __new__() বা __init__ মেথড পরিবর্তন করি।
উদাহরণ ১ - ক্লাসের প্রোপার্টি মডিফাইকারী মেটাক্লাস
class LowercaseMeta(type):
def __new__(mcs, name, bases, attrs):
lower_attrs = {}
for k, v in attrs.items():
if not k.startswith('__'):
lower_attrs[k.lower()] = v
else:
lower_attrs[k] = v
return type.__new__(mcs, name, bases, lower_attrs)
class LowercaseClass(metaclass=LowercaseMeta):
BAR = True
def HELLO(self):
print('hello')
print(dir(LowercaseClass))
LowercaseClass().hello()
আউটপুট
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'bar', 'hello'] hello
উদাহরণ ২ - ক্লাসে একটি অতিরিক্ত অ্যাট্রিবিউট যোগ করা
class ListMeta(type):
def __new__(mcs, name, bases, attrs):
attrs['add'] = lambda self, value: self.append(value)
return type.__new__(mcs, name, bases, attrs)
class MyList(list, metaclass=ListMeta):
pass
l = MyList()
l.add(1)
print(l)
def class_decorator(cls):
cls.add = lambda self, value: self.append(value)
return cls
@class_decorator
class MyList(list):
pass
l = MyList()
l.append(1)
print(l)
আউটপুট
[1] [1]
__metaclass__ অ্যাট্রিবিউট
পাইথনে, বায়া আমাদের একটি ক্লাস থাকে অথবা এর বেসগুলোর যেকোনো একটি __metaclass__ অ্যাট্রিবিউট রাখে, সেটি মেটাক্লাস হিসেবে বিবেচিত হয় অন্যথায় type হলো মেটাক্লাস। __metaclass__ অ্যাট্রিবিউট থাকতে পারে যখন আমরা একটি ক্লাস এইভাবে লিখি:
তবে কী হয় যখন আমরা এইভাবে একটি ক্লাস ডিফাইন করি:
class hello(object):
x = 10
উপরে, hello ক্লাসের কোনো __metaclass__ অ্যাট্রিবিউট নেই, তাই type ব্যবহার হয়, এবং ক্লাস তৈরি হয়:
hello = type(name, bases, dict)
যদি আমাদের hello-র একটি মেটাক্লাস ডিফাইন করা থাকে:
class hello(object):
__metaclass__ = myMetaClass
pass
এখন উপরের উদাহরণে, ক্লাস তৈরি হয় myMetaClass ব্যবহার করে type-এর বদলে। Hello = myMetaClass(name, bases, dict)