2.23. المُزخرِفات¶
إن المُزخرِف هو قطعة من البنية النحوية تغلّف دالة (أو تابعاً) داخل دالة أخرى. ويمكن للغلاف أن يضيف سلوكاً قبل الاستدعاء الأصلي وبعده، أو يستبدل القيمة المعادة، أو يرفق بيانات وصفية. والصيغة هي:
@wrapper
def f():
...
إن السطر @wrapper مكافئ لـ f = wrapper(f) -- فالدالة f تُبنى بشكل طبيعي، ثم تُسلَّم إلى wrapper، وتُعاد النتيجة إلى ربط الاسم f.
يأخذ المُزخرِف دالة ويعيد دالة جديدة.¶
2.23.1. مُزخرِفات التوابع المضمّنة¶
تأتي بعض المُزخرِفات مع Python وتُستخدم داخل أجسام الأصناف.
2.23.1.1. @property¶
يحوّل تابعاً إلى سمة محسوبة. يصل إليها المستدعي كما لو كانت سمة عادية (دون أقواس)، لكن تابعاً يُشغَّل عند كل قراءة:
class Circle:
def __init__(self, radius):
self.radius = radius
@property
def area(self):
return 3.14159 * self.radius * self.radius
c = Circle(5)
print(c.area) # 78.53975 -- no parentheses
استخدمه عندما تحتاج سمة تبدو بسيطة إلى عملية حسابية صغيرة خلفها. وإذا كان العمل مكلِّفاً، فضّل تابعاً عادياً -- إذ لا يتوقع المستدعون أن تكون قراءات السمات بطيئة.
2.23.1.2. @classmethod¶
يعرّف تابعاً يتلقى الصنف كوسيطه الأول بدلاً من نسخة. ويُسمى الوسيط الأول اصطلاحاً cls:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
@classmethod
def origin(cls):
return cls(0, 0)
p = Point.origin()
إن توابع الأصناف هي الطريقة المعيارية لتوفير بُناة بديلة -- دوال مصنع تعيد نسخة مبنية بطريقة غير افتراضية.
2.23.1.3. @staticmethod¶
يعرّف تابعاً لا يتلقى لا النسخة ولا الصنف -- فهو مجرد دالة عادية تقيم في فضاء أسماء الصنف لأسباب تنظيمية:
class Temperature:
@staticmethod
def c_to_f(c):
return c * 9 / 5 + 32
Temperature.c_to_f(100) # 212.0
استخدمه باعتدال؛ فإذا كانت دالة ما لا علاقة لها حقاً بحالة الصنف، فإن دالة عادية على مستوى الوحدة تكون عادةً أنظف.
2.23.2. كتابة مُزخرِف مخصص¶
المُزخرِف هو دالة تأخذ دالة وتعيد دالة. والصيغة الدنيا:
def log_calls(func):
def wrapper(*args, **kwargs):
print("calling", func.__name__)
return func(*args, **kwargs)
return wrapper
@log_calls
def add(a, b):
return a + b
add(2, 3)
المخرجات:
calling add
ينغلق wrapper على func ويُمرّر كل شيء إليه. وتتيح *args / **kwargs له العمل على أي دالة، وليس فقط الدوال ذات الوسيطين. هذا النمط هو أساس مُزخرِفات أكثر تفصيلاً (التوقيت، التخزين المؤقت، إعادة المحاولة عند الفشل) لكن الجوهر يبقى دائماً واحداً: خذ دالة، أعِد دالة.