קורס Python שיעור תרגול פונקציות


זה נושא דיון מלווה לערך המקורי ב- https://www.tocode.co.il/bundles/python/lessons/functions-lab
תרגיל 1 תרגול פונקציות פייתון
"""
answer 21-1
"""

def mysum(*args):
    if len(args)==0:return 0
    return sum(x for x in args if type(x)==int)

def mymul(*args):
    if len(args)==0:return 1
    return reduce(
        lambda acct,val:acct*val,
        [x for x in args if type(x)==int]
    )

# returns 60
print mysum(10, 20, 30)

# returns 30
print mysum(10, 'foo', 'bar', 20)

# returns 1
print mymul()

# returns 200
print mymul('foo', 'bar', 10, 20)
"""
answer 21-2
"""

def myFun(num=0,txt=''):
    if type(num) != int : raise Exception("Value for num , must to be int")
    if type(txt) != str: raise Exception("Value for txt , must to be text")

#Exception: Value for txt , must to be text
myFun(23123,333)

#Exception: Value for num , must to be int
myFun('23123','333')
"""
answer 21-3
"""
def SumTensDigit(*args):
    return sum([int(str(num)[-2]) for num in args])


print SumTensDigit(1120, 220, 140)
לייק 1

את השני הייתי מחלק לשתי פונקציות כדי לקבל קוד יותר קריא:

def tens_digit(number):
  """ returns the tens digit of a given value """
  return int(str(num)[-2])

def sum_tens_digits(*args):
  return sum([tens_digit(n) for n in args])
לייק 1
אני חושב שהיה צריך גם להתייחס למצב שיש מספר ללא עשרות 
"""
answer 21-3
"""
def tens_digit(number):
  """ returns the tens digit of a given value """
  if len(str(number)) < 2:return 0
  return int(str(number)[-2])

def sum_tens_digits(*args):
  return sum([tens_digit(n) for n in args])


print sum_tens_digits(1120, 220, 140)

כן מעולה! וזה בדיוק הייתרון של החלוקה לעוד פונקציה. קל יותר לראות מצבים כאלה ולטפל בהם בלי ״ללכלך״ את שאר התוכנית

"""
Answer 21-4
"""
def longer_than(min_len, *args):
    return [x for x in args if len(x) > min_len]

print longer_than(3, 'hit', 'me', 'baby', 'one', 'more', 'time')

"""
Answer 21-5
"""
def groupby(key_function, *args):
    map={}
    [set_value_per(map,key_function,word) for word in args]
    return map

def set_value_per(map,key_function,word):
    words=map.setdefault(key_function(word),[])
    words.append(word)
    return map

print groupby(lambda(s): s[0], 'hello', 'hi', 'help', 'bye', 'here')
print groupby(lambda(s): s[-1], 'hello', 'hi', 'help', 'bye', 'here')

הכתיב של הרכבת רשימות לא מתאים לכאן. אתה לא נוגע ברשימה שנוצרת ומשתמש בו רק בשביל ״תוצאת הלוואי״ כלומר הרצת הקוד בלולאה.

לולאת for רגילה תהיה הרבה יותר ברורה.

וגם ראיתי שאתה אוהב את setdefault- כדאי לדעת שיש גם מילון שנקרא defaultdict שמגיע עם setdefault בילט-אין. אפשר לקרוא עליו כאן:
https://docs.python.org/2/library/collections.html#collections.defaultdict

לא הבנתי , מה הכוונה הרכבת רשימות - ומה הכוונה “תוצאת הלוואי” ואיך צריך לעשות זאת …
ולגבי ה- setDefault זה לא שאני אוהב לעשות זאת , ככה הבנתי שעושים - למה מה זה אומר ? אם יש דרך יותר פשוטה אשמח לדעת

הרכבת רשימת - List Comprehension, כלומר כתיב מהסוג:

[x * 2 for x in range(10)]

במקרה שלך השורה:

[set_value_per(map,key_function,word) for word in args]

כתובה בתור List Comprehension. אבל היא לא צריכה להיכתב כך כי אתה לא נוגע ברשימה שיוצרה. השתמשת בכתיב רק בתור כתיב לולאה מקוצר - וזה מה שמבלבל.

נשתמש ב List Comprehension כשאנחנו באמת צריכים רשימה מתוך רשימה אחרת. נשתמש בלולאה כשאנחנו מפעילים קוד מתוך הלולאה על כל אחד מהפריטים כדי לקבל תוצאה שהיא חיצונית ללולאה.

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

קראתי - ולא הצלחתי להבין את הנואנסים וההבדל בינהם - נראה לי אותו דבר בדיוק

מה הכוונה אותו דבר? אחד מתחיל במילה for ומסתיים בנקודותיים ובשני ה for בתוך סוגריים מרובעים. בטוח אתה רואה את ההבדל בין שתי שיטות הכתיבה…

רק לחדד זו כתיבה של לולאה שמדפיסה את כל איברי הרשימה:

l = [10, 20, 30]
for i in l:
  print i

לעומתה זו כתיבה של List Comprehension שמדפיסה רשימה חדשה המורכבת מכל איברי הרשימה:

l = [10, 20, 30]
print [i for i in l]

מבחינת תוצאה מקבלים בדיוק את אותה תוצאה בשני המקרים, אבל מבחינת כתיב יש פה שתי צורות כתיבה שונות.

עכשיו אם אתה מתכוון שאתה לא רואה מתי להשתמש בצורה אחת ומתי בשניה אז הכלל הוא פשוט: אם לולאה משפיעה על דברים שנמצאים מחוץ לה (למשל בקוד שאתה כתבת לולאה משפיעה על ערכים במילון שנמצא מחוץ ללולאה) יש להשתמש בכתיב הלולאה המפורשת. אם לעומת זאת המטרה של הלולאה היא לקבל רשימה חדשה אז יש להשתמש בכתיב List Comprehension.

השאלה היא רק מה המטרה של הקוד.

הפתרונות שלי לתרגילים בנושא פונקציות:
תרגיל1:

def mysum(*li):
    sum=0
    for n in li:
        if type(n) is int:
            sum+=n
    return sum

def mymul(*li):
    mul=1
    for n in li:
        if type(n) is int:
            mul*=n
    return mul


print mysum(10,20,30,'foo',"bar")
print mysum(10, 20)
print mymul()
print mymul( 10, 20)

תרגיל2:


def twoparam(num,string):
    if type(num) is not int or type(string) is not str:
         raise Exception("Incomptable variables types")
    return True
    

print twoparam(12,'12')

תרגיל3:

def asarot(*li):
  return  sum( [int(str(num)[-2]) for num in li])

print asarot(14,1900,34,129)

תרגיל4:

def longest(num,*words):
   res= [word for word in words if len(word)>num] 
   return res       
    
print longest(3,"foxs","dddsssd","ddd")
 

תרגיל5:

def groupby(func,*words):
    obj={}
    for word in words:
        if(func(word) not in obj):
            obj[func(word)]=[]
            obj[func(word)].append(word)
        else:
            obj[func(word)].append(word)
    print obj

groupby(lambda(s):s[0],'hello','hi','help','bye','here')
לייק 1

יפה! שלושה אתגרים:

  1. בתרגיל הראשון (עם הסכום והמכפלה) מבנה שתי הפונקציות שכתבת מאוד דומה. נדמה לי שאפשר להוציא את הקוד המשותף לפונקציה שלישית וכך לחסוך את כפל הקוד.

  2. באותו תרגיל יהיה נחמד אם הפונקציות יסכימו לקבל מספרים מסוג int וגם מספרים מסוג float.

  3. בתרגיל האחרון נסה לקרוא על מבנה הנתונים defaultdict מכאן:
    https://docs.python.org/2/library/collections.html#collections.defaultdict
    ולאחר מכן לראות איך הוא יעזור לקצר את התוכנית ולוותר על הקוד הכפול (שורת ה append שמופיעה בשני הענפים של ה if)

לגבי האתגר לתרגיל 5:

from collections import defaultdict 
def groupby(func,*words):
    mydict =defaultdict(list)
    for word in words:
        mydict[func(word)].append(word)
    print mydict

groupby(lambda(s):s[0],'hello','hi','help','bye','here')

יצאה לי התשובה הזאת שנראית נכונה אבל איבר ראשון מסוג רשימה ,למה?

defaultdict(<type 'list'>, {'h': ['hello', 'hi', 'help', 'here'], 'b': ['bye']})

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

from functools import wraps

def tar1(start):
    def decorator(func):
        @wraps(func)
        def wrapped(*args):
                sum =0
                mul=1
                for arg in args:
                 if(start == 0 and  (type(arg) is int or type(arg)is float)) :
                      return func(sum,arg)
                 elif(start == 1 and  (type(arg) is int or type(arg)is float)) :
                     return func(mul,arg)
        return wrapped
    return decorator


@tar1(0)
def mysum(result,num):
    result+=num
    return result
@tar1(1)
def mymul(result,num):
    result*=num
    return result


print mysum(10,20)
print mymul(10,20)

הי,

  1. ככה נראית הדפסה של defaultdict. התשובה אחלה

  2. אל תשתמש ב decorator שם - אין בזה צורך וגם שימוש נכון לא יועיל. עדיף פשוט לכתוב פונקציה שלישית שכוללת את הקוד המשותף ולהעביר לה באמצעות פרמטר את בחירת ההתנהגות הספציפית (האם חיבור או כפל)