دروس الوحدة (4/4)
المزخرفون: الوظائف التي تعدل الوظائف
decorator هي دالة تأخذ دالة أخرى وترجع a نسخة "مزخرفة" منه. إنها طريقة قوية لإضافة السلوك (التسجيل، التوقيت، التخزين المؤقت، إعادة المحاولة، التحقق من الصحة) دون لمس نص الملف الوظيفة الأصلية.
وظائف كقيم
في بايثون، الوظائف هي كائنات: يمكنك تمريرها وإعادتها وتعيينها.
def saluta():
print("ciao")
f = saluta # NIENTE parentesi: assegno la funzione
f() # 'ciao'ديكور الحد الأدنى
def log(func):
def wrapper(*args, **kwargs):
print(f"chiamo {func.__name__}")
risultato = func(*args, **kwargs)
print(f"ho finito {func.__name__}")
return risultato
return wrapper
def somma(a, b):
return a + b
somma = log(somma) # ora somma è "wrapper"
somma(2, 3)
# chiamo somma
# ho finito somma
# 5@decorator بناء الجملة
تمت كتابة المهمة somma = log(somma) بشكل أكثر أناقة باستخدام @:
@log
def somma(a, b):
return a + bإنه ** بالضبط نفس الشيء **. @log أعلاه التعريف يعادل:
"بمجرد تعريف هذه الوظيفة، استبدلها بـ log(function)".
*args, **kwargs: قبول أي توقيع
def wrapper(*args, **kwargs):
return func(*args, **kwargs)*args يجمع الوسائط الموضعية، **kwargs وسيطات الكلمات الرئيسية. سمحوا
تكتب أغلفة تعمل مع أي وظيفة.
functools.wraps: الحفاظ على البيانات الوصفية
بدون wraps، تفقد الوظيفة المزخرفة __name__، __doc__، تلميحات:
from functools import wraps
def log(func):
@wraps(func)
def wrapper(*args, **kwargs):
...
return func(*args, **kwargs)
return wrapperمثال: @timeit
from functools import wraps
import time
def timeit(func):
@wraps(func)
def wrapper(*args, **kwargs):
t0 = time.perf_counter()
risultato = func(*args, **kwargs)
dt = time.perf_counter() - t0
print(f"{func.__name__} ha impiegato {dt*1000:.2f} ms")
return risultato
return wrapper
@timeit
def somma_grande():
return sum(range(10**6))
somma_grande()مصممو الديكور من stdlib
from functools import lru_cache
@lru_cache(maxsize=None)
def fib(n):
if n < 2: return n
return fib(n - 1) + fib(n - 2)
fib(100) # istantaneo grazie alla cache@lru_cache— يحفظ نتائج دالة خالصة.@property— يعرض الطريقة كسمة (تظهر في وحدة OOP).@staticmethod،@classmethod— تغيير كيفية تمريرself.
الديكور بالحجج
يمكن لمصممي الديكور أيضًا قبول الحجج. لتنفيذ ذلك، يجب عليك كتابة ثلاثة مستويات من الوظائف المتداخلة: الوظيفة الخارجية تستقبل وسائط المزخرف، وتستقبل الوظيفة الوسطى الوظيفة المزخرفة، وتستقبل الوظيفة الأعمق (wrapper) الوسائط الفعلية التي تم تمريرها إلى الوظيفة المزخرفة أثناء الاستدعاءات.
جربه بنفسك
اكتب ديكورًا `double_result` يستدعي الدالة المزخرفة ويعيد نتيجتها * 2. قم بتطبيقه على دالة `f(x)` التي ترجع x + 1. قم بتقييم `f(10)`.
إظهار التلميح
يستدعي المجمّع func ويعيد النتيجة مضروبة في 2.
الحل متاح بعد 3 من المحاولات
تمرين المراجعة
استخدم functools.lru_cache لتسريع وظيفة fib(n) العودية. حساب fib(30) وتعيين إلى `r`. تقييم "ر".
إظهار التلميح
@lru_cache(maxsize=None) أعلى من القيمة المحددة.
الحل متاح بعد 3 من المحاولات
التحدي الإضافي
Define a decorator `double_result` that doubles (multiplies by 2) the return value of the decorated function. Apply the decorator to the function `def sum_nums(a, b): return a + b`. Finally, evaluate `sum_nums(3, 4)`.
إظهار التلميح
يستدعي المجمع func(*args, **kwargs) ويضرب النتيجة في 2.
الحل متاح بعد 3 من المحاولات