שיעורי מודול (4/4)
דקורטורים: פונקציות שמשנות פונקציות
דקורטור היא פונקציה שלוקחת פונקציה אחרת ומחזירה א גרסה "מעוטרת" שלו. זוהי דרך רבת עוצמה להוסיף התנהגות (רישום, תזמון, שמירה במטמון, ניסיון חוזר, אימות) מבלי לגעת בגוף הפונקציה המקורית.
מתפקד כערכים
ב-Python, פונקציות הן אובייקטים: אתה יכול להעביר אותם, להחזיר אותם, להקצות אותם.
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()דקורטורים מהסטדליב
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) מקבלת את הארגומנטים המועברים בפועל לפונקציה המעוטרת במהלך קריאות.
נסה זאת בעצמך
כתוב דקורטור `תוצא_כפול` שקורא לפונקציה המעוטרת ומחזיר את התוצאה שלה * 2. החל אותו על פונקציה `f(x)` שמחזירה x + 1. הערך `f(10)`.
הצג רמז
העטיפה קוראת ל-func ומחזירה את התוצאה כפול 2.
הפתרון זמין לאחר 3 ניסיונות
סקירת התרגיל
השתמש ב-functools.lru_cache כדי להאיץ פונקציית fib(n) רקורסיבית. חשב את fib(30) והקצה ל-`r`. הערך '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 ניסיונות