📋 Table of Contents
- একটি পাইথন ডেকোরেটর কি?
- আসুন একটি সাধারণ তৈরি করি
- উপরের ডেকোরেটরে একটি সূক্ষ্ম বাগ আছে। সাজসজ্জার পর,
- আপনি যদি আপনার ডেকোরেটর কনফিগার করতে চান? যেমন,
- আপনি একটি একক ফাংশনে একাধিক ডেকোরেটর প্রয়োগ করতে পারেন। তারা প্রযোজ্য
- যে কোন কলযোগ্য বস্তু একটি সজ্জাকর হতে পারে. একটি ক্লাস ব্যবহার করা আপনাকে কলগুলির মধ্যে অবস্থা দেয়:
- আপনি ক্রমাগত ব্যবহার করবেন বেশ কয়েকটি বিল্ট-ইন ডেকোরেটর সহ পাইথন জাহাজ:
- ডেকোরেটররা বেশিরভাগ পাইথন ফ্রেমওয়ার্ককে শক্তি দেয়। এখানে উত্পাদন-গ্রেড নিদর্শন আছে:
- ভুলে যাওয়া
- পাইথন ডেকোরেটর কি?
একটি পাইথন ডেকোরেটর কি?
A পাইথন ডেকোরেটরএকটি ডিজাইন প্যাটার্ন যা আপনাকে একটি বিদ্যমান ফাংশনে নতুন আচরণ যোগ করতে দেয় — ফাংশনের কোড স্পর্শ না করে। পাইথনে, ফাংশনগুলি হল প্রথম-শ্রেণীর বস্তু: এগুলি আর্গুমেন্ট হিসাবে পাস করা যেতে পারে, ভেরিয়েবলের জন্য বরাদ্দ করা যেতে পারে এবং অন্যান্য ফাংশন থেকে ফিরে আসতে পারে। ডেকোরেটররা এই সম্পত্তি শোষণ.
|||| সিনট্যাক্স শুধু সিনট্যাকটিক চিনি। আপনি যখন লেখেন:@📋 কপি
@my_decorator
def greet(name):
return f"Hello, {name}!"
📋 কপি
greet = my_decorator(greet)
এখন বর্ধিত সংস্করণের দিকে নির্দেশ করে।greetআপনার প্রথম ডেকোরেটর: ধাপে ধাপে
আসুন একটি সাধারণ তৈরি করি
লগিং ডেকোরেটরযে কোনো ফাংশন কল করার আগে এবং পরে একটি বার্তা প্রিন্ট করে।📋 কপি
def log_calls(func):
"""Decorator that logs function entry and exit."""
def wrapper(*args, **kwargs):
print(f"→ Calling {func.__name__} with args={args}, kwargs={kwargs}")
result = func(*args, **kwargs)
print(f"← {func.__name__} returned {result!r}")
return result
return wrapper
@log_calls
def add(a, b):
return a + b
add(3, 4)
# Output:
# → Calling add with args=(3, 4), kwargs={}
# ← add returned 7
গ্রহণ করে
log_calls(মূল ফাংশন)funcএটি একটি অভ্যন্তরীণ সংজ্ঞায়িত করে- যে গ্রহণ করে
wrapper— তাই এটি যেকোন ফাংশন স্বাক্ষরের সাথে কাজ করে*args, **kwargsমোড়ক আদিকে ডাকে - , ফলাফল ক্যাপচার করে, এবং ফেরত দেয়
funcমোড়ক ফেরত দেয় — এটাকে ডাকার ফল নয় log_callsfunctools.wraps ফিক্স
উপরের ডেকোরেটরে একটি সূক্ষ্ম বাগ আছে। সাজসজ্জার পর,
ফিরে আসেadd.__name__, না'wrapper'. এই ভাঙে'add', এবং স্ট্যাক ট্রেস। এর সাথে ঠিক করুনhelp(), inspect📋 কপিfunctools.wraps:
import functools
def log_calls(func):
@functools.wraps(func) # ← copies __name__, __doc__, __module__, etc.
def wrapper(*args, **kwargs):
print(f"→ Calling {func.__name__}")
result = func(*args, **kwargs)
print(f"← {func.__name__} returned {result!r}")
return result
return wrapper
@log_calls
def add(a, b):
"""Add two numbers."""
return a + b
print(add.__name__) # 'add' ✅
print(add.__doc__) # 'Add two numbers.' ✅
@functools.wraps(func)আর্গুমেন্ট সহ সজ্জিতকারীরাআপনি যদি আপনার ডেকোরেটর কনফিগার করতে চান? যেমন,
. আপনার বাসা বাঁধার একটি অতিরিক্ত স্তর প্রয়োজন — একটি@retry(times=3)ডেকোরেটর কারখানা📋 কপি:
import functools, time
def retry(times=3, delay=1.0, exceptions=(Exception,)):
"""Retry a function up to `times` times on specified exceptions."""
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
last_err = None
for attempt in range(1, times + 1):
try:
return func(*args, **kwargs)
except exceptions as e:
last_err = e
print(f" Attempt {attempt}/{times} failed: {e}")
if attempt < times:
time.sleep(delay)
raise last_err
return wrapper
return decorator
@retry(times=3, delay=0.5, exceptions=(ConnectionError,))
def fetch_data(url):
# simulate a flaky network call
raise ConnectionError("timeout")
try:
fetch_data("https://api.example.com/data")
except ConnectionError:
print("All retries exhausted.")
. কল করুন:retry() → decorator() → wrapper()ফিরে আসেretry(times=3), যা লাগেdecoratorএবং ফিরে আসেfuncএকাধিক ডেকোরেটর স্ট্যাকিংwrapper.
আপনি একটি একক ফাংশনে একাধিক ডেকোরেটর প্রয়োগ করতে পারেন। তারা প্রযোজ্য
নিচের দিকে(সর্বোত্তম প্রথম):📋 কপি
import functools, time
def timer(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
start = time.perf_counter()
result = func(*args, **kwargs)
elapsed = time.perf_counter() - start
print(f"{func.__name__} took {elapsed:.4f}s")
return result
return wrapper
def log_calls(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print(f"Calling {func.__name__}")
return func(*args, **kwargs)
return wrapper
@timer # applied second (outer)
@log_calls # applied first (inner)
def process(n):
return sum(range(n))
process(1_000_000)
# Output:
# Calling process
# process took 0.0312s
. অর্ডারের বিষয়গুলি – বাইরের ডেকোরেটরগুলি ভিতরেরগুলিকে মোড়ানো।process = timer(log_calls(process))ক্লাস ভিত্তিক ডেকোরেটর
যে কোন কলযোগ্য বস্তু একটি সজ্জাকর হতে পারে. একটি ক্লাস ব্যবহার করা আপনাকে কলগুলির মধ্যে অবস্থা দেয়:
📋 কপি
import functools
class CallCounter:
"""Counts how many times a function is called."""
def __init__(self, func):
functools.update_wrapper(self, func)
self.func = func
self.count = 0
def __call__(self, *args, **kwargs):
self.count += 1
print(f"{self.func.__name__} called {self.count} time(s)")
return self.func(*args, **kwargs)
@CallCounter
def say_hello(name):
print(f"Hello, {name}!")
say_hello("Alice") # called 1 time(s)
say_hello("Bob") # called 2 time(s)
print(say_hello.count) # 2
আপনি ক্রমাগত ব্যবহার করবেন বেশ কয়েকটি বিল্ট-ইন ডেকোরেটর সহ পাইথন জাহাজ:
📋 কপি
class Temperature:
_kelvin_offset = 273.15
def __init__(self, celsius):
self._celsius = celsius
@property
def fahrenheit(self):
"""Computed attribute — no () needed when accessing."""
return self._celsius * 9/5 + 32
@fahrenheit.setter
def fahrenheit(self, value):
self._celsius = (value - 32) * 5/9
@classmethod
def from_kelvin(cls, kelvin):
"""Factory method — creates instance from Kelvin."""
return cls(kelvin - cls._kelvin_offset)
@staticmethod
def is_valid_celsius(value):
"""Utility — no access to instance or class."""
return value >= -273.15
t = Temperature(100)
print(t.fahrenheit) # 212.0 (property)
t.fahrenheit = 32 # setter
t2 = Temperature.from_kelvin(373.15) # classmethod
print(Temperature.is_valid_celsius(-300)) # False (staticmethod)
| প্রথম আর্গ | অ্যাক্সেস | ইউজ কেস | উদাহরণ + ক্লাস |
|---|---|---|---|
@property |
self |
গণনা করা গুণাবলী, গেটার/সেটার | শুধুমাত্র ক্লাস |
@classmethod |
cls |
কারখানার পদ্ধতি, বিকল্প নির্মাণকারী | কোনটিই না |
@staticmethod |
না | ক্লাসে ইউটিলিটি ফাংশন নামস্থান | বাস্তব-বিশ্ব ব্যবহারের ক্ষেত্রে |
ডেকোরেটররা বেশিরভাগ পাইথন ফ্রেমওয়ার্ককে শক্তি দেয়। এখানে উত্পাদন-গ্রেড নিদর্শন আছে:
1. LRU ক্যাশে দিয়ে ক্যাশিং
📋 কপি
from functools import lru_cache
@lru_cache(maxsize=128)
def fibonacci(n):
if n < 2:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
print(fibonacci(50)) # Instant — cached results
print(fibonacci.cache_info()) # CacheInfo(hits=48, misses=51, ...)
📋 কপি
import functools
def require_auth(func):
"""Decorator for protected routes."""
@functools.wraps(func)
def wrapper(request, *args, **kwargs):
token = request.headers.get("Authorization", "")
if not token.startswith("Bearer "):
return {"error": "Unauthorized"}, 401
return func(request, *args, **kwargs)
return wrapper
@require_auth
def get_user_profile(request):
return {"user": "Alice", "email": "alice@example.com"}
📋 কপি
import functools, time
from collections import defaultdict, deque
def rate_limit(calls=10, period=60):
"""Allow at most `calls` per `period` seconds per caller."""
history = defaultdict(deque)
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
now = time.time()
key = args[0] if args else "default" # use first arg as caller ID
q = history[key]
while q and now - q[0] > period:
q.popleft()
if len(q) >= calls:
raise RuntimeError(f"Rate limit exceeded: {calls} calls per {period}s")
q.append(now)
return func(*args, **kwargs)
return wrapper
return decorator
@rate_limit(calls=5, period=60)
def send_email(user_id, message):
print(f"Email sent to {user_id}: {message}")
ভুলে যাওয়া
- — বিরতি
@functools.wraps, ট্রেসব্যাক, এবং পরীক্ষার সরঞ্জামhelp()ডেকোরেটর শরীরে ফাংশন কলিং - পরিবর্তে —
return wrapper()ব্যবহার করছেন নাreturn wrapper - — পরামিতি সহ যে কোনও ফাংশন ভেঙে দেয়
*args, **kwargsপরিবর্তনযোগ্য ডিফল্ট অবস্থা কল জুড়ে ভাগ করা হয়েছে - — একটি ক্লোজার ভেরিয়েবল ব্যবহার করুন, মডিউল-স্তরের পরিবর্তনযোগ্য ডিফল্ট নয়অনুপস্থিত
- মোড়কে
return result— নিঃশব্দে ফাংশনের রিটার্ন মান গিলে নেয়📋 কপি
# ❌ Wrong — returns None
def broken(func):
def wrapper(*args, **kwargs):
func(*args, **kwargs) # no return!
return wrapper
# ✅ Correct
def fixed(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
return func(*args, **kwargs) # always return
return wrapper
এখন যেহেতু আপনি ডেকোরেটরদের বুঝতে পেরেছেন, তারা কীভাবে পাওয়ার ফ্রেমওয়ার্ক পছন্দ করে তা দেখুন
পাইথন প্রকল্পের গঠনএবং উন্নত নিদর্শন। আমাদের গাইড দেখুনপাইথন শর্টহ্যান্ড এক্সপ্রেশনআরও পাইথনিক কোড কৌশলের জন্য।প্রায়শই জিজ্ঞাসিত প্রশ্ন
পাইথন ডেকোরেটর কি?
পাইথন ডেকোরেটর হল এমন একটি ফাংশন যা ইনপুট হিসাবে অন্য একটি ফাংশন নেয় এবং একটি উন্নত সংস্করণ প্রদান করে — আসলটি পরিবর্তন না করেই।
সিনট্যাক্স হল সংক্ষেপে@আমি কখন ডেকোরেটর ব্যবহার করব?func = decorator(func).
ক্রস-কাটিং উদ্বেগের জন্য ডেকোরেটর ব্যবহার করুন: লগিং, ক্যাশিং, প্রমাণীকরণ, হার সীমিতকরণ, সময়, ইনপুট যাচাইকরণ — যে কোনো আচরণ আপনি কোড পুনরাবৃত্তি না করে একাধিক ফাংশনে প্রয়োগ করতে চান।
functools.wraps কি করে?
এটি মূল ফাংশন এর অনুলিপি
It copies the original function’s__name__, __doc__, এবং র্যাপারের অন্যান্য বৈশিষ্ট্য, ডিবাগিং, সাহায্য(), এবং পরীক্ষার সরঞ্জামগুলির জন্য পরিচয় সংরক্ষণ করে।
সাজসজ্জাকারীদের যুক্তি থাকতে পারে?
হ্যাঁ। একটি বাইরের ফ্যাক্টরি ফাংশন যোগ করুন যা আর্গুমেন্ট গ্রহণ করে এবং আসল ডেকোরেটর প্রদান করে। প্যাটার্ন:@retry(times=3) → retry()ডেকোরেটর ফেরত দেয়।
@staticmethod এবং @classmethod এর মধ্যে পার্থক্য কি?
@staticmethodকোন অন্তর্নিহিত প্রথম আর্গুমেন্ট পায় না – এটি একটি ক্লাস নেমস্পেসে একটি প্লেইন ফাংশন।@classmethodপ্রথম আর্গুমেন্ট হিসাবে ক্লাস (cls) গ্রহণ করে, ফ্যাক্টরি পদ্ধতির জন্য দরকারী।
স্ট্যাকড ডেকোরেটর কিভাবে কাজ করে?
বটম-আপ: ডেকোরেটর সবচেয়ে কাছেরdefপ্রথমে প্রয়োগ করা হয়।@A @B def f()সমানf = A(B(f)).
🔗 Share this article
✍️ Leave a Comment