Metaprogramming: Metaclasses & Descriptors
Python-এর গভীরতম OOP — metaclass ও descriptor
1. Everything Is an Object — Including Classes
In Python, a class itself is an object, and its type is its metaclass.
The default metaclass is type. Just as an instance of Dog is built by calling
Dog(), the class Dog itself is built by calling type("Dog", ...).
type। যেমন Dog() একটি instance তৈরি করে, তেমনি type("Dog", ...) Dog class-টিই তৈরি করে।
class Dog:
pass
print(type(Dog())) # <class '__main__.Dog'>
print(type(Dog)) # <class 'type'>
# Create a class dynamically with type(name, bases, namespace)
Cat = type("Cat", (), {"speak": lambda self: "meow"})
print(Cat().speak())
2. __init_subclass__ — the 80/20 Metaclass
Before reaching for a true metaclass, try __init_subclass__. It runs whenever a subclass is
defined and handles the vast majority of real use-cases: registration, validation, auto-tagging.
__init_subclass__ ভাবুন। প্রতিবার subclass সংজ্ঞায়িত হলে এটি চলে — registration, validation, auto-tagging-এর মতো বেশিরভাগ কাজ এতেই হয়।
class Plugin:
registry = []
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
Plugin.registry.append(cls)
class EmailPlugin(Plugin): pass
class SmsPlugin(Plugin): pass
print([p.__name__ for p in Plugin.registry])
3. A Real Metaclass
A metaclass inherits from type and overrides __new__ or __init__.
Use it only when you need to transform the class body itself.
type থেকে inherit করে এবং __new__ / __init__ override করে। শুধু তখনই ব্যবহার করুন যখন class-body নিজেই বদলাতে হবে।
class UpperAttrMeta(type):
def __new__(mcs, name, bases, ns):
upper = {k.upper() if not k.startswith("__") else k: v
for k, v in ns.items()}
return super().__new__(mcs, name, bases, upper)
class Config(metaclass=UpperAttrMeta):
host = "localhost"
port = 8080
print(Config.HOST, Config.PORT)
Tim Peters-এর কথা: "Metaclass ৯৯% ব্যবহারকারীর ভাবা দরকার নেই। প্রয়োজন আছে কিনা সন্দেহ হলে নেই।"
4. Descriptors — Controlled Attribute Access
A descriptor is any object that defines __get__, __set__ or
__delete__. Python's property, staticmethod, and classmethod
are all descriptors. You can use them to build typed, validated attributes.
__get__, __set__ বা __delete__ আছে। Python-এর property, staticmethod, classmethod সবই descriptor। এটি দিয়ে type-safe ও validated attribute বানানো যায়।
class Positive:
def __set_name__(self, owner, name):
self.name = "_" + name
def __get__(self, obj, owner=None):
return getattr(obj, self.name)
def __set__(self, obj, value):
if value <= 0:
raise ValueError(f"{self.name[1:]} must be positive")
setattr(obj, self.name, value)
class Product:
price = Positive()
quantity = Positive()
def __init__(self, p, q):
self.price, self.quantity = p, q
p = Product(100, 5)
print(p.price, p.quantity)
try:
p.price = -1
except ValueError as e:
print("caught:", e)
5. Class Decorators — The Middle Ground
A class decorator is a function that takes a class and returns a (usually modified) class. It's simpler than a metaclass and covers almost all practical transformations.
def auto_repr(cls):
def __repr__(self):
attrs = ", ".join(f"{k}={v!r}" for k, v in vars(self).items())
return f"{cls.__name__}({attrs})"
cls.__repr__ = __repr__
return cls
@auto_repr
class Point:
def __init__(self, x, y):
self.x, self.y = x, y
print(Point(3, 4))
6. When to Use What
7. Vocabulary (শব্দভাণ্ডার)
| Term | Meaning | বাংলায় |
|---|---|---|
| Metaclass | The class of a class; default is type. | Class-এর class; ডিফল্ট type। |
| Descriptor | Object defining __get__/__set__. | __get__/__set__-সম্পন্ন object। |
__init_subclass__ | Hook run when a subclass is created. | Subclass তৈরিতে চলা hook। |
| Class decorator | Function taking & returning a class. | Class নেয়, class ফেরত দেয় এমন function। |
| MRO | Method Resolution Order. | Method খোঁজার ক্রম। |
__set_name__ | Hook to learn the attribute name the descriptor is bound to. | Descriptor-এর attribute-নাম জানানোর hook। |
8. Practice Problems
-
Build a class dynamically with
type(name, bases, ns)that has a methodareareturning 100.type(name, bases, ns)দিয়ে dynamically একটি class বানান —areamethod যা ১০০ ফেরত দেবে।✨ Show Answer (উত্তর দেখুন)
ans1.pyShape = type("Shape", (), {"area": lambda self: 100}) print(Shape().area()) -
Write a descriptor
NonEmptyStringthat raisesValueErroron empty strings.একটি descriptorNonEmptyStringলিখুন — ফাঁকা string দিলেValueErrorদেবে।✨ Show Answer (উত্তর দেখুন)
ans2.pyclass NonEmptyString: def __set_name__(s, o, n): s.n = "_"+n def __get__(s, o, t=None): return getattr(o, s.n) def __set__(s, o, v): if not v: raise ValueError(s.n) setattr(o, s.n, v) class User: name = NonEmptyString() def __init__(self, n): self.name = n print(User("Arif").name) try: User("") except ValueError as e: print("empty blocked", e) -
Use
__init_subclass__to auto-register every subclass in a list.__init_subclass__দিয়ে প্রতিটি subclass-কে auto-register করুন।✨ Show Answer (উত্তর দেখুন)
ans3.pyclass Base: subs = [] def __init_subclass__(cls, **kw): Base.subs.append(cls.__name__) class A(Base): pass class B(Base): pass print(Base.subs) -
Why is a metaclass rarely the right tool? Answer in two sentences.Metaclass কেন সচরাচর সঠিক tool নয় — দুই বাক্যে।
✨ Show Answer (উত্তর দেখুন)
Answer: Metaclasses complicate inheritance and make code harder to read, debug and maintain. Simpler mechanisms —
property, descriptors, class decorators, and__init_subclass__— cover almost every real need and compose better.Metaclass inheritance জটিল করে, কোড পড়া-debug-maintain কঠিন করে।
property, descriptor, class decorator ও__init_subclass__— সহজ বিকল্পগুলো প্রায় সব বাস্তব প্রয়োজন পূরণ করে। -
Write a class decorator
@final_logthat prints a message each time an instance is created.একটি class decorator@final_logলিখুন — প্রতিটি instance তৈরিতে বার্তা প্রিন্ট করবে।✨ Show Answer (উত্তর দেখুন)
ans5.pydef final_log(cls): original = cls.__init__ def new_init(self, *a, **kw): print(f"creating {cls.__name__}") original(self, *a, **kw) cls.__init__ = new_init return cls @final_log class Widget: def __init__(self, n): self.n = n Widget("button"); Widget("slider")
Summary — Module 34
Everything in Python is an object, including classes — whose type is their metaclass. Descriptors
(__get__/__set__) power property and typed attributes. Class
decorators and __init_subclass__ handle 95% of metaprogramming; keep metaclasses for the
rare deep case.
property ও typed attribute তৈরি করে। ৯৫% কাজ class decorator ও __init_subclass__-এ হয় — metaclass শুধু একান্ত প্রয়োজনেই।