דילוג לתוכן
פייתון

פונקציות פייתון: איך כותבים קוד נקי עם def, פרמטרים, ערך מוחזר ופיצול נכון

אם אתם לומדים פונקציות פייתון, אתם נמצאים בדיוק בנקודה שבה קוד מתחיל להפוך מרצף פקודות קצר למשהו שאפשר להבין, לבדוק, לתקן ולהרחיב. פונקציה היא לא רק “דרך לא לחזור על קוד”; היא כלי חשיבה. היא מאפשרת לתת שם לפעולה, להפריד אחריות, לקבל קלט בצורה מסודרת ולהחזיר תוצאה שאפשר להשתמש בה בהמשך.

במאמר הזה נכתוב פונקציות אמיתיות ב־Python 3, נבין איך עובד def, מה ההבדל בין פרמטרים לארגומנטים, מתי משתמשים ב־return, איך להימנע מטעויות נפוצות, ומתי כדאי לפצל קוד לפונקציות קטנות במקום להשאיר הכול בקובץ אחד ארוך. אם אתם בתחילת הדרך, כדאי גם לשמור בצד את מדריך צעדים ראשונים להשלמת סביבת עבודה בסיסית.

מה צריך להכין לפני שמתחילים

הדוגמאות כאן משתמשות רק בספרייה הסטנדרטית של פייתון. לא צריך להתקין חבילות חיצוניות, לא צריך חשבון באף שירות, ולא צריך מפתח API. מספיק עורך טקסט ו־Python 3.

  • בלינוקס או macOS, אפשר לבדוק גרסה עם python3 --version במסוף bash.
  • ב־Windows PowerShell, נסו py --version או python --version.
  • שמרו כל דוגמה בקובץ עם סיומת .py, למשל functions_demo.py.
  • הריצו בלינוקס/macOS עם python3 functions_demo.py, וב־Windows PowerShell עם py functions_demo.py.

אם הפקודה לא מזוהה, הבעיה בדרך כלל אינה בקוד אלא בהתקנה או בנתיב ההפעלה. במקרה כזה בדקו שהתקנתם Python 3 ושסימנתם הוספה ל־PATH בזמן ההתקנה ב־Windows.

מהי פונקציה בפייתון ולמה בכלל להשתמש בה

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

אבל היתרון האמיתי עמוק יותר:

  • קריאות: השם של הפונקציה מסביר מה הקוד עושה.
  • בדיקה: קל לבדוק פונקציה קטנה בנפרד.
  • תחזוקה: שינוי במקום אחד משפיע על כל המקומות שקוראים לפונקציה.
  • הפרדת אחריות: כל פונקציה עושה דבר אחד ברור.

הצורה הבסיסית נראית כך: משתמשים במילת המפתח def, אחריה שם הפונקציה, סוגריים, נקודתיים, ואז גוף הפונקציה בהזחה.

python
def greet(name):
    # Build a greeting message
    return f"Hello, {name}!"

message = greet("Dana")
print(message)

הקוד מגדיר פונקציה בשם greet. היא מקבלת פרמטר בשם name, בונה מחרוזת ברכה ומחזירה אותה. לאחר מכן קוראים לפונקציה עם הערך "Dana" ושומרים את התוצאה במשתנה message. הפלט הצפוי הוא:

text
Hello, Dana!

פונקציות פייתון: def, פרמטרים וארגומנטים בלי להתבלבל

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

מונח איפה רואים אותו דוגמה
פרמטר בהגדרת הפונקציה def greet(name):
ארגומנט בקריאה לפונקציה greet("Dana")

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

python
def calculate_total(price, quantity=1, discount_percent=0):
    # Calculate total after applying a percentage discount
    subtotal = price * quantity
    discount = subtotal * (discount_percent / 100)
    return subtotal - discount

print(calculate_total(50))
print(calculate_total(50, 3))
print(calculate_total(price=50, quantity=3, discount_percent=10))

בדוגמה הזו price הוא פרמטר חובה, ואילו quantity ו־discount_percent מקבלים ערכי ברירת מחדל. לכן אפשר לקרוא לפונקציה עם מחיר בלבד, עם מחיר וכמות, או עם כל הערכים לפי שם. הפלט הצפוי הוא:

text
50.0
150.0
135.0

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

מה עושה return ולמה print אינו תחליף

אחת הטעויות הנפוצות בלימוד פייתון היא לחשוב ש־print ו־return עושים אותו דבר. הם לא. print מציג טקסט למסך. return מחזיר ערך למי שקרא לפונקציה.

אם פונקציה רק מדפיסה, קשה להשתמש בתוצאה שלה בהמשך. אם היא מחזירה ערך, אפשר לשמור אותו, להעביר אותו לפונקציה אחרת, לבדוק אותו בתנאי, או לחשב איתו משהו נוסף.

python
def normalize_username(username):
    # Remove surrounding spaces and convert to lowercase
    cleaned = username.strip().lower()
    return cleaned

def build_profile_line(username, city):
    # Create a display line for a user profile
    normalized = normalize_username(username)
    return f"{normalized} lives in {city}"

line = build_profile_line("  Noa_Dev  ", "Haifa")
print(line)

כאן הפונקציה normalize_username לא מדפיסה כלום. היא מחזירה מחרוזת נקייה. פונקציה אחרת, build_profile_line, משתמשת בתוצאה הזו כדי להרכיב שורה חדשה. הפלט הצפוי הוא:

text
noa_dev lives in Haifa

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

מתי לפצל קוד לפונקציות

לא כל שתי שורות צריכות פונקציה. מצד שני, קובץ של מאה שורות בלי פונקציות כמעט תמיד נהיה קשה להבנה. כלל אצבע טוב: אם יש קטע קוד שיש לו שם טבעי, כנראה שכדאי להפוך אותו לפונקציה.

שאלו את עצמכם:

  • האם אותו קוד מופיע ביותר ממקום אחד?
  • האם יש בלוק קוד שאפשר לתאר במשפט קצר, למשל “בדיקת תקינות אימייל”?
  • האם הפונקציה הנוכחית עושה גם חישוב, גם הדפסה וגם קריאת קובץ?
  • האם קשה לכתוב בדיקה ידנית פשוטה לחלק מסוים בקוד?

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

python
def average(numbers):
    # Return the average of a non-empty list
    return sum(numbers) / len(numbers)

def grade_label(score):
    # Convert a numeric score to a simple label
    if score >= 90:
        return "excellent"
    if score >= 75:
        return "good"
    if score >= 60:
        return "passed"
    return "failed"

def summarize_student(name, scores):
    # Build a summary line for one student
    avg = average(scores)
    label = grade_label(avg)
    return f"{name}: average={avg:.1f}, status={label}"

print(summarize_student("Roni", [92, 85, 88]))
print(summarize_student("Tal", [55, 61, 58]))

בדוגמה הזו כל פונקציה עושה דבר אחד. average מחשבת ממוצע, grade_label מחליטה על תווית, ו־summarize_student מחברת הכול לשורה אחת. הפלט הצפוי הוא:

text
Roni: average=88.3, status=good
Tal: average=58.0, status=failed

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

תכנון פונקציה צעד אחר צעד

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

  1. בחרו שם פעולה: למשל calculate_total, is_valid_name, format_date.
  2. החליטו מה הקלט: אילו ערכים הפונקציה צריכה לקבל?
  3. החליטו מה הפלט: האם היא מחזירה מספר, מחרוזת, רשימה, ערך בוליאני?
  4. כתבו מקרה פשוט: התחילו מקלט אחד ברור ותוצאה צפויה.
  5. הוסיפו מקרי קצה: רשימה ריקה, טקסט עם רווחים, מספר אפס, ערך חסר.

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

שמות טובים לפונקציות ולפרמטרים

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

לעומת זאת, שמות כמו do_it, handle, process_data או func1 אומרים מעט מדי. לפעמים אין ברירה זמנית, אבל אם אתם לא מצליחים לתת שם ברור לפונקציה, ייתכן שהיא עושה יותר מדי דברים.

  • במקום check, כתבו is_adult או has_items.
  • במקום data, כתבו usernames, scores או rows.
  • במקום x ו־y, השתמשו בשם שמסביר את המשמעות, אלא אם מדובר בחישוב מתמטי קצר וברור.

טעויות נפוצות והודעות שגיאה אמיתיות

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

שכחתם נקודתיים אחרי שורת def

python
def greet(name)
    return f"Hello, {name}"

הודעת שגיאה אופיינית:

output
SyntaxError: expected ':'

התיקון: להוסיף : בסוף שורת ההגדרה.

python
def greet(name):
    return f"Hello, {name}"

הזחה לא נכונה בגוף הפונקציה

python
def greet(name):
return f"Hello, {name}"

הודעת שגיאה אופיינית:

output
IndentationError: expected an indented block after function definition

בפייתון הזחה אינה קישוט; היא חלק מהתחביר. כל השורות ששייכות לגוף הפונקציה חייבות להיות מוזחות באותה צורה. מקובל להשתמש בארבעה רווחים.

קראתם לפונקציה בלי להעביר ארגומנט חובה

python
def add(a, b):
    return a + b

print(add(5))

הודעת שגיאה אופיינית:

output
TypeError: add() missing 1 required positional argument: 'b'

התיקון: להעביר את כל הארגומנטים החובה, או להגדיר ערך ברירת מחדל אם זה מתאים לוגית.

python
def add(a, b=0):
    return a + b

print(add(5))

הקוד המתוקן יחזיר 5, כי b מקבל ברירת מחדל של אפס.

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

python
def show_total(price):
    print(price * 2)

total = show_total(10)
print(total)

הפלט יהיה:

text
20
None

למה? כי הפונקציה הדפיסה 20, אבל לא החזירה ערך. בפייתון, פונקציה בלי return מחזירה אוטומטית None. אם רוצים להשתמש בתוצאה, כתבו כך:

python
def calculate_double(price):
    return price * 2

total = calculate_double(10)
print(total)

הפלט הצפוי הוא:

text
20

פרמטרים עם ברירת מחדל: נוח, אבל בזהירות

ערכי ברירת מחדל מועילים מאוד כאשר יש התנהגות נפוצה. לדוגמה, אם רוב החישובים מתבצעים ללא הנחה, הגיוני להגדיר discount_percent=0. אבל יש כלל חשוב: אל תשתמשו ברשימה ריקה כערך ברירת מחדל אם אתם מתכוונים לשנות אותה בתוך הפונקציה.

במקום לכתוב פונקציה שמקבלת items=[] ואז מוסיפה אליה פריטים, עדיף להשתמש ב־None וליצור רשימה חדשה בתוך הפונקציה. זה מונע מצב שבו קריאות שונות לפונקציה חולקות בטעות את אותה רשימה.

python
def add_item(item, items=None):
    # Create a new list when no list is provided
    if items is None:
        items = []
    items.append(item)
    return items

print(add_item("apple"))
print(add_item("banana"))
print(add_item("pear", ["orange"]))

הפלט הצפוי הוא:

text
['apple']
['banana']
['orange', 'pear']

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

איך יודעים שפונקציה קטנה מדי או גדולה מדי

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

פונקציה כנראה גדולה מדי אם:

  • השם שלה כולל “וגם”: למשל “טען קובץ וגם חשב ממוצע וגם הדפס דוח”.
  • יש בה כמה רמות עמוקות של if ו־for.
  • אתם מתקשים להסביר במשפט אחד מה היא מחזירה.
  • שינוי קטן דורש לגעת בכמה אזורים לא קשורים בתוך אותה פונקציה.

פונקציה כנראה קטנה מדי אם היא רק עוטפת פעולה אחת בלי להוסיף משמעות. למשל, פונקציה בשם print_name שמכילה רק print(name) לא תמיד מועילה. לעומת זאת, אם היא חלק מממשק אחיד או מסתירה פורמט מורכב, ייתכן שהיא כן מוצדקת.

תרגול קצר: להפוך קוד ארוך לפונקציות

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

  1. סמנו את החלק שמחשב את הסכום.
  2. העבירו אותו לפונקציה שמחזירה מספר.
  3. סמנו את החלק שבונה הודעה.
  4. העבירו אותו לפונקציה שמחזירה מחרוזת.
  5. השאירו את print בסוף התוכנית.

גישה כזו מתאימה במיוחד ללימוד עצמי של פייתון למתחילים: לא מנסים לכתוב קוד “מושלם” מהשורה הראשונה, אלא משפרים אותו בהדרגה. אותו הרגל יעזור גם כשתעברו לנושאים כמו עבודה עם קבצים, ביטויים רגולריים, Git, או שאילתות SQL. אפשר לחזור אל צעדים ראשונים אם אתם רוצים לוודא שסביבת העבודה שלכם מסודרת לפני שממשיכים.

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

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

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

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