الدرس 7 من 8
الـ Decorators
الـ @ اللي هتشوفها فوق دوال كتير.
الفكرة ببساطة
الـ decorator زي جراب الموبايل: الموبايل هو هو، بس الجراب ضاف عليه حماية وحامل. الـ decorator بياخد function، ويلفها بكود زيادة قبلها أو بعدها، من غير ما تلمس الكود الأصلي.
الأساس: الدوال في بايثون قيم عادية
def shout(text): return text.upper() say = shout # no () -> we pass the function itself print(say("hello")) def apply(func, value): # a function that receives another function return func(value) print(apply(shout, "ahlan"))
أول decorator: قيس الوقت
import time from functools import wraps def timer(func): @wraps(func) # keeps the original function's name def wrapper(*args, **kwargs): start = time.time() result = func(*args, **kwargs) # call the original function elapsed = time.time() - start print(f"{func.__name__} took {elapsed:.2f}s") return result return wrapper @timer # same as: slow_report = timer(slow_report) def slow_report(): time.sleep(1.2) return "report ready" print(slow_report())
wrapper الدالة الجديدة اللي بتلف الأصلية.*args بتستقبل أي عدد من الـ arguments العادية.**kwargs بتستقبل أي عدد من الـ keyword arguments.@wraps بتحافظ على اسم ووصف الدالة الأصلية.🌍 مثال واقعي: صلاحيات الدخولفي أي موقع، صفحات زي «طلباتي» مش المفروض تفتح غير لو اليوزر عامل login. بدل ما تكتب الشرط ده في كل صفحة، بتعمل decorator وتحطه فوق كل صفحة محتاجاه.
current_user = {"name": "Sara", "logged_in": False}
def login_required(func):
def wrapper(*args, **kwargs):
if not current_user["logged_in"]:
print("Please log in first")
return None
return func(*args, **kwargs)
return wrapper
@login_required
def show_orders():
print(f"Orders for {current_user['name']}: #1024, #1031")
show_orders()
current_user["logged_in"] = True
show_orders()الـ @property: decorator جاهز هتستخدمه كتير
class Rectangle: def __init__(self, width, height): self.width = width self.height = height @property def area(self): # computed, but used like an attribute return self.width * self.height r = Rectangle(4, 5) print(r.area) # no () needed
💡 هتقابلها فين؟في FastAPI هتكتب
@app.get("/users") فوق كل endpoint، وفي PyTorch هتشوف @torch.no_grad(). انت مش لازم تكتب decorators كتير، بس لازم تفهمها لما تشوفها.