קורס Python שיעור תרגול Decorators


זה נושא דיון מלווה לערך המקורי ב- https://www.tocode.co.il/bundles/python/lessons/decorators-lab

אחלה פתרונות אבל איפה התרגילים?

הי
התרגילים עצמם נמצאים בטאב ״טקסט״ (כפתור למעבר ואב נמצא מעל הסרטון)

אגב כמעט לכל שיעור באתר יש טקסט מלווה בטאב טקסט, שהרבה פעמים כולל גם הרחבות ותוספות על מה שמופיע בוידאו. ממליץ להסתכל שם אחרי שרואים את הוידאו (בכל השיעורים)

"""
Answer 23-4
"""
from functools import wraps

def memoize(f):
     data={}
     @wraps(f)
     def wapper(n):
         if data.has_key(n) :return data[n]
         res=f(n)
         data.__setitem__(n,res)
         return res
     return wapper


@memoize
def fib(n):
    print "fib(%d)" % n
    if n <= 2:
        return 1
    else:
        return fib(n-1) + fib(n-2)


print fib(10)

התשובה בשאלה - לא נכונה מכיוון שבפונקציה רשמת split - צריך להסיר אאת ה- split
"""
Answer 25-5
"""
from functools import wraps

def debug(f):
    @wraps(f)
    def wapper(*args,**kwargs):
        print "[]Debug: args=%s , kwargs=%s" % (args,kwargs)
        res=f(*args,**kwargs)
        print "[]Debug: result=%s" % (res)
        return res
    return wapper



@debug
def sum_digits(n):
    digits = str(n)
    result = 0

    for char in digits:
        result += int(char)

    return result

print sum_digits(1531221)

תודה על התיקון - עדכנתי את הטקסט!

שאלה על משהו שמבלבל אותי מדוע אחרי החזרה של פונקציית המעטפת עדיין בזיכרון
התוכנית יש שמירה של האובייקט data גם אחרי קריאות נוספות לפונקציית המעטפת ,היא לא אמורה להתנקות מהזיכרון אחרי החזרה הראשונה של פונקצית העיטור?


"""Write a decorator called after5 that takes a
function and returns a new version of it that ignores
first 5 invocations"""

def after5(f):
    data = { 'counter' : 0 }
        
    def wrapper(*args, **kwargs):
        data['counter'] += 1
        if data['counter'] > 5: return f(*args, **kwargs)
        
    return wrapper

@after5
def doit(): print "Yo!"

# ignore the first 5 calls
doit()
doit()
doit()
doit()
doit()

# so only print yo once
doit()

ומדוע על אותו אופן של התוכנית הקודמת ,התוכנית הנ"ל לא עובדת?


def after5(func):
     counter=0
     def warpped(*args,**kwargs):
        if counter !=5:
         counter+=1
         pass
        else:
         return func(*args,**kwargs)
     return warpped

@after5
def doit(): print "Yo!"

doit() 
doit()
doit()
doit() 
doit()
doit() 
doit()

לגבי ניהול זיכרון יש שיעור על זה בקורס המתקדם. שווה להעיף מבט ואולי זה יעזור להבין יותר טוב מה הולך שם:
https://www.tocode.co.il/bundles/advanced-python3/lessons/memory

לגבי התוכנית השניה יש בעיה שהפונקציה הפנימית לא מזהה שמשתנה counter שלה הוא אותו אחד מהפונקציה החיצונית. גם על זה יש שיעור בקורס המתקדם ואני חושב שכדאי להעיף מבט שם כדי לקבל תמונה יותר מקיפה:
https://www.tocode.co.il/bundles/advanced-python3/lessons/variable-scope

אם אחרי צפיה בשיעורים אלה עוד יהיו שאלות תרגיש חופשי להמשיך לפרסם כאן

לגבי הcounter נראה לי שהבנתי למה זה לא עובד מפני שבפונקציית warpped המשתנה counter נוצר כמקומי לפונקציה לפי מה שאני מבין בגלל ההשמה counter+=1 שגורמת לפייתון ליצור משתנה זה כמקומי למרות שניסתי לתקן לפי
nonlocal אבל פייתון זורק לי על זה שגיאה:

def after5(func):
     counter=0
     def warpped(*args,**kwargs):
         nonlocal counter
        if counter !=5:
         counter+=1
         pass
        else:
         return func(*args,**kwargs)
     return warpped

@after5
def doit(): print "Yo!"

doit() 
doit()
doit()
doit() 
doit()
doit() 
doit()

ולגבי השאלה הראשונה הבנתי שבאובייקט דאטה לא מת מכיוון שכל חזרה שלו מהפונקצייה אז כויכול הפונצקיה מצביעה עליו במרחב שלה ואז כל הפעלה נוספת שלה כויכול מעדכנת אותו

לייק 1

מדויק.

בפייתון 2 אין nonlocal (זה מילה חדשה של python3), הטריק במקום זה הוא להגדיר מערך למשל כך:

def after5(func):
     counter=[0]
     def warpped(*args,**kwargs):
        if counter[0] !=5:
         counter[0]+=1
         pass
        else:
         return func(*args,**kwargs)
     return warpped

לייק 1

מקסים… שיהיה יום טוב ורק דברים טובים… :heart_eyes:
חייב לציין שהקורס שלך בפייתון מהנה

לייק 1