Python Hebrew Booklet 2.5

You might also like

Download as pdf or txt
Download as pdf or txt
You are on page 1of 46

‫‪Python 2.

5‬‬

‫תוכן עניינים‬
‫פרק ‪ _:1‬מבוא ‪4 ..........................................................................................................‬‬
‫מהי ‪4.................................................................................................................................... ?Python‬‬
‫‪ Python‬לעומת ‪4...............................................................................................................................C‬‬
‫הפעלת ‪4................................................................................................................................ Python‬‬

‫פרק ‪ _:2‬ה‪ Interpreter-‬ומאחורי הקלעים ‪6 ..................................................................‬‬


‫משחקים עם ה‪6................................................................................................................ Interpreter-‬‬
‫משתנים והשמות )‪6......................................................................................................... (Assignments‬‬
‫איך ‪ Python‬עובד )מימוש( ‪7.................................................................................................................‬‬

‫פרק ‪ _:3‬טיפוסי נתונים ואופרטורים ‪9 .........................................................................‬‬


‫מספרים ‪9.........................................................................................................................................‬‬
‫מחרוזות ‪11 ........................................................................................................................................‬‬
‫מחרוזות ‪13 ............................................................................................................................ Unicode‬‬
‫רשימות ‪13 ........................................................................................................................................‬‬
‫‪14 ........................................................................................................................................... Tuples‬‬
‫מילונים‪15 .........................................................................................................................................‬‬

‫פרק ‪ _:4‬בקרת זרימה‪17 .............................................................................................‬‬


‫‪17 .................................................................................................................................................. if‬‬
‫‪17 ............................................................................................................................................ while‬‬
‫‪17 ................................................................................................................................................ for‬‬
‫‪19 ................................................................................................................................. range, xrange‬‬
‫‪20 ............................................................................................................................... break, continue‬‬
‫‪20 ............................................................................................................................................. pass‬‬

‫פרק ‪ _:5‬קלט ופלט ‪21 ................................................................................................‬‬


‫הדפסה למסך ‪21 ..............................................................................................................................‬‬
‫קלט מהמקלדת ‪21 ............................................................................................................................‬‬
‫קבצים ‪21 ..........................................................................................................................................‬‬

‫פרק ‪ _:6‬פונקציות ‪23 ..................................................................................................‬‬


‫הגדרת פונקציות ‪23 ...........................................................................................................................‬‬
‫‪ pass‬בפונקציות ‪23 .............................................................................................................................‬‬
‫פרמטרים‪23 ......................................................................................................................................‬‬
‫תיעוד ‪25 ...........................................................................................................................................‬‬
‫משתנים בפונקציות ‪26 .......................................................................................................................‬‬
‫החזרת ‪-Tuple‬ים מפונקציה ‪27 .............................................................................................................‬‬

‫פרק ‪28 ........................................................................ map, reduce, filter, lambda_:7‬‬


‫‪28 ..............................................................................................................................................map‬‬
‫‪28 .......................................................................................................................................... reduce‬‬
‫‪28 ............................................................................................................................................. filter‬‬
‫‪29 .......................................................................................................................................... lambda‬‬
‫שימוש ב‪ reduce ,map-‬ו‪ filter-‬ביחד ‪29 ...................................................................................................‬‬
‫מילה על יעילות ‪30 ............................................................................................................................‬‬

‫פרק ‪ _:8‬מודולים ‪31 ...................................................................................................‬‬


‫מהו מודול? ‪31 ...................................................................................................................................‬‬
‫אוסף פונקציות שנמצא בקובץ אחר‪Error! Bookmark not defined..........................................................‬‬
‫הרצת קבצי ‪ Python‬כמו תוכניות ‪32 ......................................................................................................‬‬
‫כתיבת מודולים של ממש ‪Error! Bookmark not defined........................................................................‬‬

‫עמוד ‪2‬‬
‫‪Python 2.5‬‬

‫מודולים מובנים ב‪Error! Bookmark not defined.........................................................................Python-‬‬


‫‪Error! Bookmark not defined......................................................................................................... dir‬‬

‫פרק ‪ :_9‬מודולים נפוצים ‪34 ........................................................................................‬‬


‫‪34 ..................................................................................................................................... os‬‬ ‫המודול‬
‫‪35 .................................................................................................................................... sys‬‬ ‫המודול‬
‫‪35 ................................................................................................................................ string‬‬ ‫המודול‬
‫‪35 ................................................................................................................................. math‬‬ ‫המודול‬

‫פרק ‪ _:10‬מחלקות וירושה ‪36 .....................................................................................‬‬


‫מושגי יסוד‪36 ....................................................................................................................................‬‬
‫‪ Python‬ו‪36 ................................................................................................................................. OOP-‬‬
‫הגדרת מחלקה ‪36 .............................................................................................................................‬‬
‫שימוש במחלקות שיצרנו ‪37 ................................................................................................................‬‬
‫הסתרת איברים במחלקה ‪39 ..............................................................................................................‬‬
‫ירושה‪39 ...........................................................................................................................................‬‬
‫איך כל זה משתלב עם מה שלמדנו עד כה ‪41 ......................................................................................‬‬

‫פרק ‪42 .............................................................................................. Exceptions_:11‬‬


‫מה זה ‪-Exception‬ים?‪42 .......................................................................................................................‬‬
‫למה זה טוב? ‪44 ................................................................................................................................‬‬
‫למה זה רע? ‪44 ..................................................................................................................................‬‬
‫התוכנית הראשונה שלי )שזורקת‪Error! Bookmark not defined......................................................... (...‬‬
‫להעביר את השגיאה הלאה ‪44 ...........................................................................................................‬‬
‫אפשר לזרוק גם עצמים‪Error! Bookmark not defined...........................................................................‬‬

‫פרק ‪ _:12‬תרגילים ‪45 .................................................................................................‬‬


‫סתם תרגיל ‪45 ..................................................................................................................................‬‬
‫כספומט ‪45 .......................................................................................................................................‬‬
‫יומן פגישות ‪45 ..................................................................................................................................‬‬
‫מחשבון ממש משוכלל ‪45 ..................................................................................................................‬‬

‫עמוד ‪3‬‬
‫‪Python 2.5‬‬

‫פרק ‪_:1‬מבוא‬
‫מהי ‪?Python‬‬
‫‪ Python‬היא שפת ‪ Scripting‬נוחה לשימוש שהפכה למאוד פופולרית בשנים האחרונות‪ Python .‬נוצרה בשנות ה‪90-‬‬
‫המוקדמות ע"י גידו ואן רוסם )‪ (Guido van Rossum‬ב‪ ,Stichting Mathematisch Centrum-‬כשפת המשך לשפה שנקראה‬
‫‪ .ABC‬בשנת ‪ 1995‬גידו המשיך את פיתוח בחברה ששמה ‪ ,(CNRI) Corporation for National Research Initiatives‬ואף‬
‫הוציא מספר גירסאות של השפה‪ .‬במאי ‪ 2000‬גידו וצוות הפיתוח של ‪ Python‬עברו ל‪ BeOpen.com-‬כדי לייסד את‬
‫"‪ ."BeOpen Python Labs team‬באוקטובר ‪ 2000‬בצוות עבר ל‪ ,Digital Creations-‬וב‪ 2001-‬נוסד ‪Python Software‬‬
‫‪ ,(PSF) Foundation‬שהוא ארגון ללא מטרות רווח‪ Digital Creations .‬היא אחת המממנות של ‪ .PSF‬כל מה שקשור ל‪-‬‬
‫‪ Python‬הוא ‪ ,Open Source‬כלומר הקוד פתוח ונגיש לכולם‪ ,‬ולכל אחד מותר לבצע בו שינויים ולהפיצו מחדש‪ .‬אתר‬
‫הבית של ‪ PSF‬הוא ‪.http://www.python.org/psf/‬‬
‫כאשר אומרים "שפת ‪ "Scripting‬מתכוונים שאין צורך בהידור )‪ (Compilation‬וקישור )‪ (Linkage‬של תוכניות‪ .‬ב‪Python-‬‬
‫פשוט כותבים ומריצים‪ .‬כל סביבת עבודה של ‪ Python‬מגיעה עם ‪ Interpreter‬שמאפשר כתיבה ישירה של פקודות אליו‪,‬‬
‫אפילו בלי צורך לכתוב תוכנית או קובץ‪ .‬בצורה כזו מאוד נוח להתנסות בשפה‪ ,‬לבצע חישובים מהירים )עוד תכונה חזקה‬
‫של ‪ (Python‬ולבדוק דברים קטנים במהירות‪ ,‬בלי הצורך לכתוב תוכנית שלמה‪.‬‬
‫ל ‪ Python‬יתרונות רבים על פני שפות ‪ Scripting‬אחרות‪ .‬ראשית‪ Python ,‬פשוטה בהרבה ללימוד‪ ,‬לקריאה ולכתיבה‬
‫משפות אחרות )שחלקן מתעללות במתכנת ובמי שצריך לקרוא קוד כתוב(‪ Python .‬גורמת לקוד שכתוב בה להיראות‬
‫מסודר‪ ,‬ברור ומובנה )נראה כיצד מאוחר יותר(‪ .‬מודל המימוש של השפה ברור בהרבה ממימוש שפות אחרות‪ ,‬ובכך‬
‫תורם להבנת השפה ולשליטה בה‪.‬‬
‫שנית‪ Python ,‬מכיל בתוכו אוסף מכובד מאד של ספריות סטנדרטיות‪ ,‬כלומר ספריות שניתן להסתמך על קיומן בכל‬
‫מימוש של ‪ .Python‬בין הכלים השימושיים ניתן למצוא יכולות התמודדות עם קבצים דחוסים )‪ ,(zip‬תכנות לתקשורת‬
‫‪ ,TCP/IP‬כלים מרובים לתכנות בסביבת האינטרנט‪ ,‬ממשק משתמש גרפי )‪ ,(GUI‬ספריות לטיפול בטקסט ומחרוזות )כמו‬
‫כן עיבוד טקסטואלי למיניו(‪ ,‬עבודה עם פונקציות מתקדמות של מערכת ההפעלה‪ ,‬תמיכה בתכנות מבוזר ) ‪Distributed‬‬
‫‪ ,(Development‬יכולת טיפול אינטנסיבית בקבצי ‪ XML‬ונגזרותיהם‪ ,‬ועוד הרבה הרבה הרבה דברים! כמו כן ‪Python‬‬
‫מטפלת במידע בינארי )מידע שאינו טקסטואלי( בצורה הרבה יותר טובה משפות מתחרות‪.‬‬
‫בנוסף‪ ,‬כמו שניתן לכתוב תוכניות קטנות ב‪ ,Python-‬קיימים בה כלים לכתיבת תוכניות גדולות‪ ,‬ואף מודולים שלמים‪.‬‬
‫‪ Python‬תומכת בתכנות מכוון עצמים )‪ ,(OOP‬חריגות )‪ ,(Exceptions‬מבני נתונים )‪ (Data Structures‬וקישוריות גם ל‪ ,C-‬או‬
‫כל שפה שניתן לקרוא לה מ‪.C-‬‬
‫דבר נוסף שכדאי לדעת על ‪ Python‬הוא שיש לה מספר גרסאות‪ .‬אמנם יש תאימות לאחור‪ ,‬אבל בגרסאות החדשות‬
‫)‪ 2.0‬ומעלה( יש הרבה תכונות חדשות ונוחות לשימוש‪ .‬בחוברת זו נלמד את גרסה ‪.2.5‬‬

‫לסיכום – ‪ Python‬היא כלי רב‪-‬עצמה בידיו של כל מתכנת המכבד את עצמו!‬

‫‪ Python‬לעומת ‪C‬‬
‫אוקיי‪ ,‬אז ‪ Python‬היא שפה מגניבה שמאפשרת לעשות הרבה דברים בקלות ובמהירות‪ ,‬לא צריך להסתבך עם‬
‫קומפיילרים ולינקרים ואפילו אפשר לא לכתוב את התוכניות בקבצים אם רוצים‪ .‬אבל‪ ,‬זה לא אומר שמפסיקים‬
‫להשתמש ב‪:C-‬‬
‫בראש ובראשונה‪ Python ,‬היא שפת ‪ – Scripting‬מה שאומר ש‪ Python-‬רצה לאט יותר מ‪ .C-‬כאשר נעדיף ביצועים על‬
‫מהירות כתיבת הקוד )או נוחות הכתיבה(‪ ,‬נשתמש ב‪ C-‬או כל שפה מקומפלת אחרת‪ .‬בנוסף‪ ,‬ניתן לכתוב מודולי הרחבה‬
‫ל‪ Python-‬באמצעות ‪ C‬ו‪ ,C++-‬ולכן שפות אלה הן בעלות שימוש רב גם בעת העבודה עם ‪.Python‬‬

‫הפעלת ‪Python‬‬
‫דבר אחרון שנעשה במבוא המצומצם שלנו הוא להפעיל את ‪.Python‬‬
‫כיום‪ Python ,‬מופצת יחד עם כל ה‪-Distribution-‬ים הפופולריים של ‪ ,RedHat, Slackware, Corel, Debian) Linux‬ועוד‪,(...‬‬
‫וניתן להוריד סביבות פיתוח של ‪ Python‬ל‪) Windows-‬למשל ‪ ActivePython‬של ‪ ,ActiveState‬גירסה ‪ 2.5‬ומעלה(‪.‬‬

‫כמו כן‪ ,‬ניתן לבקר באתר ‪ www.python.org‬ולמצוא שם גרסאות מוכנות ל – ‪ Windows‬כולל התקנה נוחה ופשוטה‪.‬‬

‫שימו לב‪ :‬הנכם מקבלים‪ ,‬בנוסף לחוברת זו‪ ,‬גם חוברת ודיסק של לינוקס‪ .‬ניתן להפעיל את ‪ python‬מהלינוקס‬
‫שקיבלתם‪.‬‬

‫כדי להפעיל את ‪ Python‬בלינוקס‪ ,‬פשוט מקלידים את הפקודה ‪ python‬ב‪ console-‬ומקבלים את ה‪ prompt-‬של ‪:Python‬‬

‫‪$ python‬‬
‫)‪Python 2.5.2 (r252:60911, Apr 21 2008 11:12:42‬‬
‫‪[GCC 4.2.3 (Ubuntu 4.2.3-2ubuntu7)] on linux2‬‬
‫‪Type “help”, “copyright”, “credits” or “license” for more information.‬‬
‫>>>‬

‫כדי להפעיל את ‪ Python‬מחלונות‪ ,‬צריך כמובן להתקין את אחת מסביבות העבודה שקיימות כיום לחלונות‪ .‬אם התקנת‬
‫את הסביבה המצויינת למעלה‪ ,‬ניתן להפעיל את הסביבה מ‪Start  Programs  ActiveState ActivePython  Python -‬‬
‫‪.Interpreter Shell‬‬

‫עמוד ‪4‬‬
‫‪Python 2.5‬‬

‫במהלך כל החוברת‪ ,‬הדוגמאות שיירשמו יילקחו מסביבת העבודה בלינוקס‪ ,‬אבל אין שום הבדל בין שתי סביבות‬
‫העבודה )בהנחה שעובדים עם גירסה עדכנית – ‪ 2.2‬ומעלה(‪.‬‬

‫חשוב מאוד! חוברת זו מלמדת את גירסה ‪ 2.5‬של ‪ ,Python‬ולכן כאשר אתם מורידים גירסה של ‪ ,Python‬יש לבדוק שזו‬
‫גירסה ‪ 2.5‬ומעלה‪.‬‬

‫עמוד ‪5‬‬
‫‪Python 2.5‬‬

‫פרק ‪_:2‬ה‪ Interpreter-‬ומאחורי הקלעים‬


‫משחקים עם ה‪Interpreter-‬‬
‫אחרי שהפעלנו את ‪ ,Python‬הגיע הזמן להתחיל לשחק איתו קצת‪...‬‬
‫בהנחה שהפעלת את התוכנה הנכונה‪ ,‬על המסך מופיע ה‪ prompt-‬של ‪ – Python‬סימן של שלושה חיצים‪:‬‬

‫>>>‬

‫ב‪ prompt-‬הזה ניתן למעשה לכתוב כל פקודת ‪ ,Python‬והיא תורץ כל עוד היא חוקית ותקינה‪.‬‬
‫אבל הדבר הראשון שננסה הוא לא פקודה‪ ,‬אלא ביטוי‪ .‬נרשום את הביטוי ‪:1+1‬‬

‫‪>>> 1+1‬‬
‫‪2‬‬

‫הביטוי נכון‪ ,‬אבל זה לא ממש מרשים‪ ...‬אמרנו של‪ Python-‬יש יכולות חישוב מהירות‪ .‬בואו ננסה משהו קצת יותר מסובך‪:‬‬

‫‪>>> 2**2**2**2**2‬‬

‫את התוצאה כבר לא נרשום כאן‪ ...‬הסבר מלא על השורה )ולמה רשמנו ‪ 2L‬במקום ‪ 2‬רגיל( יופיע בפרק על טיפוסי‬
‫נתונים‪ .‬אם הרצת את השורה האחרונה על המחשב שלך‪ ,‬לקח לו כמה שניות להגיע לתוצאה‪ ,‬אבל הוא כתב על המסך‬
‫ממש הרבה מספרים‪ .‬מה שעשינו בשורה האחרונה היה‪:‬‬

‫‪2‬‬
‫‪22‬‬
‫‪2‬‬
‫‪2‬‬
‫וכמו שבוודאי הבנת‪ ** ,‬זה חזקה‪.‬‬
‫‪ Python‬יודע גם לטפל במחרוזות‪ :‬מחרוזות נכתבות כרצף של תווים בין שני תווים של גרש בודד ) ' (‪ ,‬או בין שני תווים‬
‫של גרשיים )"(‪ .‬כמובן‪ ,‬אי‪-‬אפשר לשלב )מחרוזת שנפתחת בגרש אחד ונסגרת בגרשיים(‪.‬‬

‫’!‪>>> ‘Hello, World‬‬


‫’!‪‘Hello, World‬‬

‫עוד על מחרוזות וכל הדברים שניתן לעשות בהן‪ ,‬בפרק הבא‪.‬‬


‫הדבר האחרון שנלמד הוא _‪ .‬סימן ה _ )‪ (Underscore‬ב‪ Python-‬מציין את התוצאה האחרונה שחושבה ע"י ה‪-‬‬
‫‪ .Interpreter‬כך למשל‪:‬‬

‫>>>‬ ‫‪1+1‬‬
‫‪2‬‬
‫>>>‬ ‫‪_+2‬‬
‫‪4‬‬
‫>>>‬ ‫_‬
‫‪4‬‬
‫>>>‬ ‫‪_**2‬‬
‫‪16‬‬

‫משתנים והשמות )‪(Assignments‬‬


‫כמו ברוב שפות‪-‬התכנות‪ ,‬גם ב‪ Python-‬יש משתנים‪ .‬אבל‪ ,‬שלא כמו בכל שפת תכנות‪ ,‬ב‪ Python-‬אין צורך להכריז על‬
‫משתנים או על הסוג שלהם‪.‬‬
‫ב‪ ,Python-‬משתנה נוצר כאשר מציבים לתוכו ערך‪ ,‬וסוג המשתנה נקבע לפי הסוג של אותו ערך התחלתי‪ .‬דוגמה‪:‬‬

‫‪>>> x=5‬‬
‫)‪>>> type(x‬‬
‫>’‪<type ‘int‬‬

‫בדוגמה הזאת נוצר משתנה בשם ‪ ,x‬וערכו ההתחלתי הוא ‪ .5‬כיוון ש‪ 5-‬הוא מספר שלם )יש לשים לב להבדל בין ‪ 5‬ל‪-‬‬
‫‪ ,5.0‬כמו ב‪ (C-‬סוג המשתנה הוא ‪.int‬‬
‫את סוג המשתנה מקבלים באמצעות הפונקצייה המובנית ‪ ,type‬המקבלת בסוגריים את המשתנה ומחזירה את הסוג‬
‫שלו‪.‬‬
‫כאשר מציבים למשתנה ערך חדש‪ ,‬גם סוג המשתנה מתעדכן בהתאם‪ .‬אם ‪ x‬היה ‪ int‬עד עכשיו‪ ,‬ונציב לתוכו ערך חדש‪,‬‬
‫סוג המשתנה ישתנה בהתאם לערך החדש‪:‬‬
‫עמוד ‪6‬‬
‫‪Python 2.5‬‬

‫‪>>> x=5.0‬‬
‫)‪>>> type(x‬‬
‫>’‪<type ‘float‬‬

‫ועכשיו הסוג של ‪ x‬הוא ‪.float‬‬


‫אילוצי שמות המשתנים עובדים כמו ב‪:C-‬‬

‫‪>>> x=5‬‬
‫‪>>> y=x‬‬
‫‪>>> y‬‬
‫‪5‬‬

‫ואפילו ניתן ליצור השמות מרובות בשורה אחת‪:‬‬

‫‪>>> x, y = 17, 42‬‬


‫‪>>> x‬‬
‫‪17‬‬
‫‪>>> y‬‬
‫‪42‬‬

‫בנוסף‪ ,‬כדי להדפיס ערך של משתנה‪ ,‬ניתן להשתמש בפקודה ‪) print‬זה כבר שימושי בתוך תוכניות‪ ,‬לא ב‪:(Interpreter-‬‬

‫‪>>> print x‬‬


‫‪17‬‬

‫הפקודה ‪ ,print‬בנוסף לפקודות אחרות )יש להבדיל בין פקודות לבין פונקציות( מופיעה ללא סוגריים‪ .‬זאת משום שזו‬
‫פקודה ולא פונקציה‪ .‬ההבדל בין פונקציה לפקודה הוא שפקודה היא כל מילת מפתח של ‪ Python‬שאיתה כותבים את‬
‫בקרת הזרימה של התוכנית )הכוונה לפקודות ‪ ,print ,while ,if‬וכו'(‪ .‬פונקציה היא אוסף של פקודות‪ ,‬פונקציות אחרות‬
‫ופונקציות מובנות שאותן אספנו ביחד כדי ליצור פעולה בסיסית‪.‬‬

‫נקודה נוספת שיש לציין היא ש‪ Python-‬היא ‪ ,Case-Sensitive‬כלומר יש הבדל בין משתנה בשם ‪ a‬לבין משתנה בשם ‪– A‬‬
‫אלו הם שני משתנים שונים‪ ,‬משום שהאות ‪ A‬איננה האות ‪ .a‬חוקים אלה הם כמו החוקים של ‪.C‬‬
‫בנוסף לטיפוסים המוכרים ב‪ ,C-‬ב‪ Python-‬יש מספר טיפוסים מובנים )‪ (Built In‬נוספים )את כולם נסקור בפרק הבא(‪.‬‬
‫אחד מהם הוא רשימה‪ .‬יצירה רשימה נעשית באופן הבא‪:‬‬

‫]‪>>> l = [1, 2, 3‬‬

‫כעת יש רשימה בשם ‪) l‬האות ‪ L‬קטנה( שמכילה את המספרים ‪ .3 ,2 ,1‬האינדקס של האיבר הראשון הוא אפס‪ ,‬וניתן‬
‫להתייחס לרשימה כולה או לאיבר בודד בה‪:‬‬

‫‪>>> l‬‬
‫]‪[1, 2, 3‬‬
‫]‪>>> l[0‬‬
‫‪1‬‬

‫סקירה מלאה של הרשימה ושאר הטיפוסים המובנים נמצאת בפרק הבא‪.‬‬

‫איך ‪ Python‬עובד )מימוש(‬


‫סעיף זה מתאר את דרך המימוש המקובלת של ‪ .Python‬אין הדבר אומר שיש רק דרך אחת לממש את ‪ ,Python‬אלא‬
‫שזוהי הדרך המקובלת לממש את ‪.Python‬‬
‫המשתנים ב‪ Python-‬הם לא יותר מאשר מצביעים – כל משתנה הוא מצביע לאובייקט‪ .‬לכל אובייקט יש סוג )אובייקט‬
‫של מספר‪ ,‬אובייקט של מחרוזת‪ ,‬וכד'(‪ .‬משום שמשתנה הוא מצביע‪ ,‬נוח לשנות "ערכים" של משתנים – רק משנים את‬
‫העצם אליו המשתנה מצביע‪ ,‬וה"ערך" שלו משתנה‪.‬‬
‫כאשר משתנה מצביע לעצם‪ ,‬ויוצרים השמה למשתנה אחר )ע"י ‪ ,(x=y‬יוצרים הצבעה חדשה אל העצם‪ ,‬ולא עצם חדש‪.‬‬
‫כאשר משנים את העצם המקורי‪ ,‬כל מי שהצביע אליו מושפע‪ .‬בדוגמה הבאה ניצור רשימה‪ ,‬וננסה להשים אותה‬
‫למשתנה אחר‪:‬‬

‫>>>‬ ‫]‪x = [1, 3, 7‬‬


‫>>>‬ ‫‪y = x‬‬
‫>>>‬ ‫‪x‬‬
‫‪[1,‬‬ ‫]‪3, 7‬‬
‫>>>‬ ‫‪y‬‬
‫‪[1,‬‬ ‫]‪3, 7‬‬
‫>>>‬ ‫‪x[1] = 6‬‬
‫>>>‬ ‫‪x‬‬
‫‪[1,‬‬ ‫]‪6, 7‬‬

‫עמוד ‪7‬‬
‫‪Python 2.5‬‬

‫‪>>> y‬‬
‫]‪[1, 6, 7‬‬

‫כפי שניתן לראות‪ ,‬יצרנו רשימה במשתנה ‪ ,x‬והשמנו אותה למשתנה ‪ .y‬כתוצאה מכך‪ ,‬לא נוצרה רשימה חדשה‪ ,‬אלא‬
‫הצבעה לרשימה הקיימת‪ .‬כאשר שינינו את הרשימה הקיימת‪ ,‬כל מי שהצביע אליה הושפע מכך‪.‬‬

‫עמוד ‪8‬‬
‫‪Python 2.5‬‬

‫פרק ‪_:3‬טיפוסי נתונים ואופרטורים‬


‫מספרים‬
‫אז נתחיל ממספרים‪ ,‬הטיפוס הפשוט ביותר‪ .‬מספר יכול להיות שלם‪ ,‬עשרוני או ארוך‪ ,‬כאשר יש הבדל ברור בין שלושת‬
‫סוגי המספרים‪ ,‬ולכל‪-‬אחד מהסוגים האלה יש ‪ type‬מיוחד משלו‪ .‬ה‪ type-‬של מספר שלם הוא ’‪ ,‘int‬ה‪ type-‬של מספר‬
‫עשרוני הוא ’‪ ‘float‬וה‪ type-‬של מספר ארוך הוא ’‪) ‘long int‬הכוונה ב‪ type-‬היא לסוג המשתנה שמוחזר ע"י הפונקצייה‬
‫המובנית )(‪.(type‬‬
‫מספרים שלמים הם אותם משתני ‪ 32-bit‬בעלי סימן מ‪ .C-‬הגבול שלהם הוא ‪ +2,147,483,647‬עד ‪.-2,147,483,648‬‬
‫מספר שלם הוא כל מספר שלם שאין לו תוספות אחריו )שבר עשרוני‪ ,‬או אותיות בעלות משמעות‪ ,‬אותן נראה בהמשך(‬
‫ושאינו חורג מהתחום הנ"ל‪ .‬אם ננסה לדוגמה להכריז על משתנה שלם‪:‬‬
‫‪>>> x = 34‬‬
‫)‪>>> type(x‬‬
‫>'‪<type 'int‬‬

‫אז ‪ x‬הוא משתנה מסוג ‪ .int‬אם ננסה להכריז על מספר שלם שחורג מהתחום‪ ,‬הוא יומר אוטומטית ל‪:long-‬‬

‫‪>>> 4389678923476892347‬‬
‫‪4389678923476892347L‬‬

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

‫‪>>> 2**30‬‬
‫‪1073741824‬‬
‫‪>>> _*2‬‬
‫‪2147483648L‬‬

‫כלומר‪ ,‬מספרים שלמים מתנהגים כמו ב‪ C-‬מבחינת גבולות וייצוג‪ ,‬אבל אין באמת מגבלה על גודל מספר בפיתון‪ ,‬מכיוון‬
‫שבמידת הצורך מספר מומר ל‪ long-‬שיכול לתמוך במספר בכל גודל שהוא‪.‬‬
‫הכוונה ב"כל גודל שהוא" היא ש‪ Python-‬דואגת לשמור משתנה בגודל הדרוש כך שיחזיק את כל המספר‪ ,‬ודואגת‬
‫לשנות את גודל המשתנה בהתאם עם כל שינוי של ערך המספר‪.‬‬

‫למרות שאין בכ צורך אמיתי‪ ,‬אפשר ליצור משתנה ארוך כמו שיוצרים משתנה שלם רגיל‪ .‬ההבדל היחיד הוא הוספת‬
‫האות ‪ L‬אחרי המספר )‪ L‬עבור ‪ .(Long‬אין משמעות להוספת ‪ L‬קטנה או גדולה‪ ,‬אבל מומלץ בתור הרגל לכתוב תמיד ‪L‬‬
‫גדולה – הרבה יותר ברור שהכוונה ליצירת מספר ארוך‪ ,‬ולא הספרה אחת )‪.(1‬‬

‫‪>>> 2L‬‬
‫‪2L‬‬
‫)_(‪>>> type‬‬
‫>'‪<type 'long‬‬

‫וכך יצרנו משתנה ארוך‪.‬‬

‫סוג המשתנה הבא והאחרון לסעיף זה הוא המספר העשרוני‪ .‬ייצוג המספר העשרוני שונה ממספר שלם‪ ,‬ולכן חלות עליו‬
‫מגבלות מסוימות‪ .‬גם למספר עשרוני יש גבולות )הגבולות תלויים במימוש של המספר העשרוני – האם זה מספר‬
‫עשרוני של ‪ 32-bit‬או של ‪ ,(64-bit‬אבל אין לו טיפוס מקביל לשם הארוך‪.‬‬
‫יצירת משתנה עשרוני היא כמו ב‪ ,C-‬ע"י כתיבת מספר עם נקודה עשרונית ושבר )אפשר שבר ‪ ,0‬רק כדי להצהיר שזה‬
‫מספר עשרוני(‪.‬‬

‫‪>>> 21.0‬‬
‫‪21.0‬‬

‫כמו כן‪ ,‬כאשר משלבים בחישוב מסוים מספר עשרוני‪ ,‬התוצאה הופכת אוטומטית להיות עשרונית‪ ,‬אלא אם כן‬
‫משתמשים באחת מפונקציות ה‪) casting-‬אותן נראה בהמשך(‪.‬‬

‫‪>>> 1.0/2‬‬
‫‪0.5‬‬

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

‫‪>>> 21L/7.0‬‬
‫‪3.0‬‬

‫עמוד ‪9‬‬
‫‪Python 2.5‬‬

‫אבל אם לוקחים מספר ממש ממש ארוך ומבצעים חישוב עם מספר עשרוני‪ ,‬תיווצר שגיאה‪:‬‬

‫‪>>> (2L**2**2**2**2) / 3.0‬‬


‫‪Traceback (most recent call last):‬‬
‫>‪File “<stdin>”, line 1, in <module‬‬
‫‪OverflowError: long int too large to convert to float‬‬

‫בסיסים‪ :‬בסיסי ספירה ב‪ Python-‬נכתבים ומתנהגים כמו ב‪:C-‬‬


‫כאשר רוצים לייצג מספר בבסיס ‪ ,Hexadecimal) 16‬או בקיצור ‪ (Hex‬משתמשים בקידומת ‪:0x‬‬

‫‪>>> 0xBEE‬‬
‫‪3054‬‬

‫‪ Python‬כמובן יציג את המספר בייצוג עשרוני‪ ,‬וזוהי דרך מצויינת להמיר מבסיס לבסיס ממש מהר‪ .‬אפשר לעשות גם את‬
‫הפעולה ההפוכה‪ ,‬בעזרת הפונקצייה המובנית )(‪ hex‬שמקבלת מספר ומחזירה מחרוזת המכילה את המספר בייצוג‬
‫הקסהדצימלי‪:‬‬

‫‪>>> 0xBEE‬‬
‫‪3054‬‬
‫)_(‪>>> hex‬‬
‫’‪‘0xbee‬‬

‫ייצוג מספרים בבסיס ‪ (Octal) 8‬נעשה ע"י הוספת אפס לפני המספר אותו רוצים לייצג‪.‬‬

‫‪>>> 045‬‬
‫‪37‬‬

‫כמו הפונקצייה )(‪ ,hex‬קיימת פונקצייה מובנית בשם )(‪ oct‬שממירה מספר דצימלי למחרוזת בייצוג אוקטלי‪:‬‬

‫)‪>>> oct(45‬‬
‫’‪‘055‬‬

‫אופרטורים‪ :‬בתת‪-‬סעיף זה נראה את כל האופרטורים שיכולים לפעול על מספרים‪ .‬יש לשים לב כי יש אופרטורים‬
‫שפועלים בין מספרים לבין טיפוסים אחרים‪ ,‬אבל כאן נציג רק את האופרטורים הקשורים למספרים‪.‬‬
‫חיבור )‪ ,(+‬חיסור )‪ (-‬וכפל )*( פועלים כמו בשפת ‪ .C‬כלומר‪ ,‬כאשר יש פעולה בין ‪ 2‬אופרנדים זהים‪ ,‬התוצאה היא‬
‫מהסוג של האופרנדים‪ .‬כאשר האופרנדים לא זהים‪ ,‬התוצאה תהיה מהטיפוס ה"יותר מתקדם"‪ :‬בכל פעולה בה מעורב‬
‫מספר עשרוני התוצאה תהיה עשרונית‪ .‬אם בפעולה לא מעורב משתנה עשרוני‪ ,‬אבל מעורב משתנה ארוך‪ ,‬התוצאה‬
‫תהיה ארוכה‪.‬‬
‫חילוק )‪ (/‬גם פועל כמו ב‪ ,C-‬וכאשר ישנם טיפוסי נתונים שונים שמעורבים בחישוב‪ ,‬הכלל לגבי חיבור חיסור וכפל קובע‬
‫גם כאן‪ .‬כאשר יש חילוק בין שלמים‪ ,‬התוצאה תמיד שלמה‪ .‬לעומת זאת‪ ,‬אם רוצים תוצאה עשרונית‪ ,‬חייב להיות מעורב‬
‫מספר עשרוני‪.‬‬
‫אם רוצים לאלץ את ‪ Python‬לייצר תוצאה עשרונית‪ ,‬אבל משתמשים רק במשתנים שלמים‪ ,‬ניתן להשתמש בפונקצייה‬
‫)(‪ float‬כדי להמיר את אחד המשתנים השלמים למספר עשרוני‪ ,‬ועל‪-‬ידי כך לגרום לתוצאה להיות עשרונית‪:‬‬

‫‪>>> x = 8‬‬
‫‪>>> y = 3‬‬
‫‪>>> x/y‬‬
‫‪2‬‬
‫‪>>> float(x) / y‬‬
‫‪2.6666666666666665‬‬

‫כמובן‪ ,‬כדי לקבל תוצאה עשרונית נכונה בדוגמה האחרונה‪ ,‬לא ניתן לעשות את הדבר הבא‪:‬‬

‫)‪>>> float(x/y‬‬
‫‪2.0‬‬

‫במקרה כזה קודם ‪ x/y‬מחושב‪ ,‬ורק אז הוא מומר למשתנה עשרוני‪.‬‬

‫מודולו )‪ (%‬לא מתנהג כמו בשפת ‪ ,C‬הוא קצת יותר משוכלל‪ .‬אופרטור המודולו יכול לקבל מספרים שלמים רגילים‪,‬‬
‫ארוכים וגם משתנים עשרוניים‪ .‬התוצאה במקרים בהם המספרים שלמים וארוכים ברורה‪ ,‬היא מחזירה את השארית של‬
‫החלוקה בין שני המספרים‪ ,‬והטיפוס )כמו בכל האופרטורים האחרים( יהיה לפי הכלל של חיבור וחיסור‪.‬‬
‫במקרה בו אחד האופרטורים הוא משתנה עשרוני‪ ,‬התוצאה מחושבת כמספר שלם )כלומר‪ ,‬מחושב המודולו של שני‬
‫הפרמטרים‪ ,‬והתוצאה הנה בצורת מספר עשרוני(‪.‬‬
‫דוגמה להתנהגות זו‪:‬‬

‫‪>>> 3.0 % 6.0‬‬


‫‪3.0‬‬
‫עמוד ‪10‬‬
‫‪Python 2.5‬‬

‫‪>>> 6.0 % 3.0‬‬


‫‪0.0‬‬
‫‪>>> 2.5 % 3.5‬‬
‫‪2.5‬‬

‫בדוגמה הראשונה חושב המודולו של המספרים ‪ 3‬ו‪ ,6-‬כי הם בסך‪-‬הכל שלמים שמיוצגים בצורה עשרונית‪ .‬בדוגמה‬
‫השניה חושב המודולו ההפוך )והתוצאה בהתאם(‪.‬‬
‫בדוגמה השלישית לעומת זאת‪ ,‬חושבה השארית של ‪ 2.5‬לחלק ל‪.3.5-‬‬

‫בולואנים‬
‫טיפוסים בוליאנים הם האחים החורגים של המספרים‪ .‬טיפוס בוליאני יכול לקבל רק את הערכים ‪ True‬או ‪,False‬‬
‫ובהרבה פונקציות של פיתון )וכמובן גם בפונקציות שניצור בעצמנו‪ ,‬כמו שעוד נראה בהמשך( מקובל להחזיר ערכים‬
‫אלה כאשר הערך יכול להיות "כן" או "לא"‪.‬‬
‫לדוגמה‪:‬‬
‫‪>>> 5 == 6‬‬
‫‪False‬‬

‫ניסינו לבדוק האם ‪ 5‬שווה ל‪) 6-‬האופרטור == הוא בכל אותה משמעות כמו ב‪ ,(C-‬וקיבלנו את התשובה "לא"‪.‬‬

‫הסיבה שבוליאנים דומים למספרים היא שפיתון יודעת לתרגם‪ ,‬במידת הצורך‪ ,‬בין בוליאנים למספרים שלמים רגילים‪.‬‬
‫‪ True‬מתורגם ל‪ False ,1-‬מתורגם ל‪ ,0-‬והתרגום מתבצע רק כאשר מנסים לבצע פעולות חשבוניות על בוליאנים‪ ,‬למשל‪:‬‬

‫‪>>> True + 1‬‬


‫‪2‬‬
‫‪>>> 0 * True‬‬
‫‪0‬‬
‫‪>>> False * True‬‬
‫‪0‬‬
‫‪>>> False + True‬‬
‫‪1‬‬
‫‪>>> True/False‬‬
‫‪Traceback (most recent call last):‬‬
‫>‪File "<stdin>", line 1, in <module‬‬
‫‪ZeroDivisionError: integer division or modulo by zero‬‬

‫הדוגמה האחרונה מנסה לחלק ב‪ ,False-‬שהוא למעשה חילוק ב‪ ,0-‬וכמובן אסור‪.‬‬

‫מחרוזות‬
‫מחרוזות ב‪ Python-‬מיוצגות בצורה הפוכה מ‪ :C-‬ב‪ ,C-‬מחרוזת היא אוסף של תווים‪ .‬ב‪ ,Python-‬מחרוזת היא טיפוס נתונים‬
‫מובנה‪ ,‬ותו הוא מחרוזת באורך ‪ .1‬ייצוג זה מקל מאוד על העבודה עם מחרוזות – מה שמצריך ב‪ C-‬שימוש בפונקציות של‬
‫הספריה >‪ <string.h‬מצריך כאן שורת קוד אחת קצרצרה‪.‬‬

‫יצירת מחרוזת תיעשה באחת מהצורות הבאות‪:‬‬

‫= ‪>>> str‬‬ ‫”!‪“Look how easy‬‬


‫‪>>> str‬‬
‫‪‘Look how‬‬ ‫’!‪easy‬‬
‫= ‪>>> rts‬‬ ‫’!‪‘Look how easy‬‬
‫‪>>> rts‬‬
‫‪‘Look how‬‬ ‫’!‪easy‬‬

‫כמו שניתן לראות‪ ,‬מחרוזות ניתן ליצור בשתי צורות‪ :‬המחרוזת נמצאת בין ‪ 2‬תווים של גרשיים או בין ‪ 2‬תווים של גרש‬
‫בודד‪ .‬כמובן‪ ,‬אם מחרוזת נמצאת בין ‪ 2‬תווים של גרשיים‪ ,‬ניתן לכלול בה גרש בודד )בלי ’\‘(‪ ,‬ולהפך‪ .‬כמובן‪ ,‬אפשר‬
‫להשתמש בתו ה‪ ‘\’-‬כדי לכלול את התווים האלה במחרוזות‪.‬‬
‫כמו כן‪ ,‬כל הצירופים של ’\‘ ותו אחריהם מ‪ C-‬תקפים ב‪ ‘\n’ :Python-‬לשורה חדשה‪ ‘\r’ ,‬לתחילת השורה‪‘\b’ ,‬‬
‫לחזור תו אחד אחורה‪ ‘\t’ ,‬עבור טאב‪ ,‬וכו'‪...‬‬
‫כמו כן‪ ,‬ב‪ Python-‬יש מנגנון מובנה לפירמוט )‪ (Formatting‬של מחרוזות )מה שעושה )(‪ .(printf‬זה נעשה ע"י כתיבת כל‬
‫ה‪ %-‬המוכרים כבר מ‪ C-‬לתוך המחרוזת וכתיבת כל הפרמטרים אחרי המחרוזת‪:‬‬

‫)’‪>>> “I am %d years old, and my cat’s name is %s.” % (17, ‘Shmulik‬‬


‫”‪“I am 17 years old, and my cat’s name is Shmulik.‬‬

‫בפועל‪ ,‬אחרי המחרוזת יש את התו ’‪ ,‘%‬ואחריו אנחנו מעבירים ‪) Tuple‬הטיפוס יוצג בהמשך פרק זה( של כל הפרמטרים‪,‬‬
‫לפי הסדר‪ .‬אם מעבירים מספר לא מדויק של פרמטרים )למשל‪ ,‬רשמנו רק ‪ %d‬במחרוזת‪ ,‬והעברנו שני פרמטרים(‪ ,‬יש‬
‫שגיאה‪ .‬כמו כן‪ ,‬אם מעבירים פרמטר שהוא לא מהסוג שהעברנו ב‪) %-‬מחרוזת עבור ‪ ,%d‬וכו'(‪ ,‬גם יש שגיאה‪.‬‬
‫פירמוט המחרוזות של ‪ Python‬הרבה יותר מוגן ונוח מזה של ‪ ,C‬הוא לא מצריך קריאה לפונקציה‪ ,‬וניתן להכניס אותו בכל‬
‫מקום‪ ,‬אפילו בתוך קריאה לפונקציה )בפרמטר‪ ,‬במקום להכניס סתם מחרוזת רגילה‪ ,‬מכניסים מחרוזת מפורמטת(‪:‬‬
‫עמוד ‪11‬‬
‫‪Python 2.5‬‬

‫‪>>> def func(s):‬‬


‫‪...‬‬ ‫‪print s*5‬‬
‫‪...‬‬
‫))”‪>>> func(“yanti%s” % (“parazi‬‬
‫‪yantiparaziyantiparaziyantiparaziyantiparaziyantiparazi‬‬

‫כעת נסקור כמה פונקציות שימושיות מאוד‪ .‬חלק מפונקציות אלה מובנות ב‪ Python-‬עצמה‪ ,‬וחלקן של טיפוס המחרוזת‪.‬‬
‫)(‪ chr‬מקבלת כקלט מספר המייצג את ערך ה‪ ASCII-‬של תו מסוים‪ ,‬ומחזירה מחרוזת ובה תו אחד שערך ה‪ ASCII-‬שלו‬
‫הוא הערך שקיבלה הפונקציה כפרמטר‪:‬‬

‫)‪>>> chr(97‬‬
‫’‪‘a‬‬
‫)‪>>> chr(65‬‬
‫’‪‘A‬‬

‫)(‪ str‬לעומתה מקבלת משתנה ומנסה להמיר אותו למחרוזת‪ .‬הפונקציה מסוגלת לקבל יותר מטיפוסים בסיסיים‪ ,‬אפילו‬
‫רשימות ומילונים )נראה בהמשך(‪:‬‬

‫)‪>>> str(1234‬‬
‫’‪‘1234‬‬
‫)]‪>>> str([1,2,3‬‬
‫’]‪‘[1, 2, 3‬‬

‫הפונקציה )(‪ split‬עושה דבר דומה ל‪ split-‬ב‪ ,Perl-‬כאשר היא מקבלת מחרוזת ותו‪ ,‬ומפצלת את המחרוזת לרשימה‪ ,‬כאשר‬
‫התו שהיא קיבלה מפריד בין האיברים ברשימת הפלט‪ .‬לדוגמה‪:‬‬

‫)‘ ‘(‪>>> ‘look at me’.split‬‬


‫]’‪[’look’, ‘at’, ‘me‬‬

‫הפונקציה )(‪ ,join‬לעומתה‪ ,‬עושה בדיוק ההפך – היא מקבלת רשימה‪ ,‬ומופעלת על מחרוזת‪ .‬הפלט הוא מחרוזת‬
‫המורכבת מכל איברי הרשימה‪ ,‬והמחרוזת הנתונה ביניהם‪:‬‬

‫)]’‪>>> ‘ ‘.join([’Hello,’, ‘world’, ‘I’, ‘am’, ‘a’, ‘joined’, ‘string‬‬


‫’‪‘Hello, world I am a joined string‬‬

‫דבר שלא ניתן לעשות עם מחרוזות הוא לשנות את ערכו של תו בודד‪ .‬הסיבה לכך נעוצה במימוש של ‪ ,Python‬שכמו‬
‫שכבר ציינו בנוי ממצביעים‪ .‬מחרוזת היא מצביע לעצם שמכיל את המחרוזת‪ .‬הביטוי הבא‪:‬‬

‫’‪>>> s = ‘ugifletzet‬‬
‫]‪>>> s[1‬‬
‫’‪‘g‬‬

‫מחזיר תת‪-‬מחרוזת שמכילה רק תו אחד במחרוזת‪ ,‬ולא מאפשר השמה לערך זה‪ .‬אם נרצה לשנות את המחרוזת‪ ,‬ניאלץ‬
‫להזין את המשתנה בערך חדש לגמרי‪.‬‬
‫בסעיף על רשימות נראה שבאמצעות ‪ Slicing‬ניתן לקבל תת‪-‬מחרוזת )ולא רק תו אחד(‪.‬‬

‫בנוסף‪ ,‬קיימות במחרוזות פונקציות לשינוי ה‪ Capitalization-‬של מחרוזות‪ ,‬כלומר כל נושא האותיות הקטנות והגדולות‬
‫באנגלית‪ .‬הפונקציה )(‪ capitalize‬מקבלת מחרוזת ומחזירה את אותה המחרוזת‪ ,‬כאשר האות הראשונה במילה הראשונה‬
‫מתחילה באות גדולהף והשאר קטנות‪.‬‬
‫הפונקציה )(‪ upper‬מחזירה מחרוזת בה כל האותיות גדולות‪ .‬הפונקציה )(‪ lower‬עושה אותו הדבר‪ ,‬רק מחזירה מחרוזת‬
‫בה כל האותיות קטנות‪.‬‬

‫‪ strip‬מקבלת מחרוזת ומסירה ממנה את תווי ה‪ whitespace-‬שנמצאים בקצוות המחרוזת‪ .‬למשל‪ ,‬הנה המחרוזת הבאה‬
‫אחרי ‪:strip‬‬

‫‪>>> s = ‘ power rangers‬‬ ‫‪\t‬‬ ‫‘‬


‫)(‪>>> s.strip‬‬
‫’‪‘power rangers‬‬

‫הפונקציה ‪ index‬מקבלת מחרוזת ותת‪-‬מחרוזת‪ ,‬ומחזירה את המקום הראשון בו תת‪-‬המחרוזת מופיעה בתוך המחרוזת‪.‬‬
‫אם לא נמצא מקום כזה‪ ,‬הפונקציה זורקת שגיאה )יילמד בהמשך בפרק על ‪ .(Exceptions‬הפונקציה ‪ find‬עושה בדיוק‬
‫אותו הדבר‪ ,‬אבל אם היא לא מוצאת את תת‪-‬המחרוזת היא מחזירה ‪.-1‬‬

‫עמוד ‪12‬‬
‫‪Python 2.5‬‬

‫מחרוזות ‪Unicode‬‬
‫דבר נוסף שנתמך ע"י ‪ Python‬הוא מחרוזות ‪ – Unicode‬מחרוזות אלו הן מחרוזות בהן כל תו מיוצג ע"י שני בתים‪ ,‬וכך ניתן‬
‫לייצג יותר תווים בטיפוס אחד‪ .‬התמיכה ב‪ Unicode-‬היא לא לשימוש שוטף ב‪ ,Python-‬אלא יותר עבור תאימות עם‬
‫מודולים שיש להם ממשק הדורש ‪.Unicode‬‬
‫מחרוזת ‪ Unicode‬נוצרת בדיוק כמו מחרוזת רגילה‪ ,‬רק שלפני המחרוזת יש את התו ’‪:‘u‬‬

‫’‪>>> u’Unicode String‬‬


‫’‪u’Unicode String‬‬
‫)_(‪>>> type‬‬
‫>’‪<type ‘unicode‬‬

‫רשימות‬
‫רשימה היא טיפוס שמחזיק טיפוסים אחרים‪ ,‬שומר על הסדר שלהם‪ ,‬מאפשר להוסיף‪ ,‬להסיר ולקבל איברים מכל מקום‬
‫ברשימה‪ ,‬וניתן לעבור על כל אחד מהאיברים שברשימה‪ .‬ב‪ ,Python-‬רשימה היא טיפוס מובנה‪ ,‬ובנוסף‪ ,‬רשימה אחת‬
‫יכולה להחזיק איזה טיפוס שנרצה‪ ,‬ואפילו כמה סוגי טיפוסים בבת‪-‬אחת‪.‬‬
‫יצירת רשימה נעשית ע"י רשימה בה איבריה מופיעים בין סוגריים מרובעות‪:‬‬

‫]‪>>> x = [1, 2, 3, 4, 5‬‬


‫‪>>> x‬‬
‫]‪[1, 2, 3, 4, 5‬‬

‫זאת הרשימה שמכילה את המספרים ‪ 1‬עד ‪.5‬‬


‫עכשיו נוסיף לרשימה את האיבר ‪ – 6‬את זה ניתן לעשות ב‪ 2-‬דרכים‪ .‬הראשונה‪ ,‬לחבר שתי רשימות‪:‬‬

‫]‪>>> x = x + [6‬‬
‫‪>>> x‬‬
‫]‪[1, 2, 3, 4, 5, 6‬‬

‫והשניה היא להשתמש בפונקציה )(‪ append‬הפועלת על רשימה‪:‬‬

‫)‪>>> x.append(6‬‬
‫‪>>> x‬‬
‫]‪[1, 2, 3, 4, 5, 6‬‬

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

‫‪>>> x * 3‬‬
‫]‪[1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6‬‬

‫‪ – Slicing‬או בעברית "חיתוך"‪ ,‬היא הפעולה בה אנחנו לוקחים רשימה קיימת ויוצרים ממנה רשימה חדשה‪ ,‬ע"י חיתוך של‬
‫חלק מהרשימה המקורית‪ .‬ה‪ Slicing-‬נעשה ע"י ציון האינדקסים של תחילת וסיום החיתוך‪ .‬לדוגמה‪ ,‬הנה רשימה חדשה‬
‫שמורכבת מאינדקסים ‪ 1‬עד )לא כולל!( ‪:3‬‬

‫]‪>>> x[1:3‬‬
‫]‪[2, 3‬‬

‫המספר הראשון )לפני הנקודותיים( הוא האינדקס ממנו מתחיל החיתוך‪ ,‬והמספר השני הוא האינדקס שבו יסתיים‬
‫החיתוך‪ ,‬אבל הוא בעצמו לא ייכלל ברשימה הנוצרת‪.‬‬
‫מטעמי נוחות‪ ,‬כאשר רוצים להעתיק קטע רשימה שמתחיל מיד בהתחלה שלה‪ ,‬או מסתיים מיד בסופה‪ ,‬אין צורך לציין‬
‫את האינדקס הראשון )תמיד ‪ (0‬או את האינדקס האחרון )תמיד אורך הרשימה(‪ ,‬וניתן להשמיט אותו‪ .‬לדוגמה‪ ,‬הנה‬
‫הרשימה עד אינדקס ‪:4‬‬

‫]‪>>> x[:4‬‬
‫]‪[1, 2, 3, 4‬‬

‫והנה הרשימה מאינדקס ‪ 4‬ועד סופה‪:‬‬

‫]‪>>> x[4:‬‬
‫]‪[5, 6‬‬

‫כמו כן‪ ,‬כאשר משמיטים גם את התחלת הרשימה וגם את סופה‪ ,‬מקבלים את כל הרשימה‪:‬‬

‫]‪>>> x[:‬‬
‫]‪[1, 2, 3, 4, 5, 6‬‬
‫עמוד ‪13‬‬
‫‪Python 2.5‬‬

‫לכאורה זהו בזבוז מקום‪ ,‬הרי ניתן לרשום סתם ‪ x‬ולקבל את הרשימה כמו שהיא‪ ,‬אבל מיד נראה למה זה טוב‪.‬‬

‫כמו שכבר ציינו מקודם‪ ,‬ב‪ Python-‬משתנים הם בסך‪-‬הכל מצביעים‪ ,‬כלומר שם של משתנה הוא מצביע לטיפוס מסוים‪.‬‬
‫כאשר משתנה מצביע לטיפוס כלשהו – בין אם זה טיפוס מובנה או טיפוס שנוצר ע"י המשתמש )בהמשך החוברת נראה‬
‫כיצד עושים את זה(‪ ,‬הוא מצביע לכתובת מסוימת בזיכרון‪ .‬כאשר מבצעים השמה )עושים =( בין שני משתנים‪,‬‬
‫והמשתנים הם לא מטיפוס "פשוט" )לא מספר(‪ ,‬ההשמה למעשה מעתיקה את המצביע ממשתנה אחד למשתנה‬
‫האחר‪.‬‬
‫בדוגמה הבאה ניצור רשימה בשם ‪ ,x‬נשים אותה במשתנה ‪ ,y‬נוסיף איבר לרשימה ‪ y‬ונראה כיצד הרשימה ‪ x‬משתנה גם‬
‫כן‪:‬‬

‫>>>‬ ‫]‪x = [1, 2, 3‬‬


‫>>>‬ ‫‪y = x‬‬
‫>>>‬ ‫)‪y.append(4‬‬
‫>>>‬ ‫‪x‬‬
‫‪[1,‬‬ ‫]‪2, 3, 4‬‬
‫>>>‬ ‫‪y‬‬
‫‪[1,‬‬ ‫]‪2, 3, 4‬‬

‫הדוגמה האחרונה מראה תכונה חזקה מאוד של ‪ – Python‬אין בה צורך במצביעים‪ ,‬כיוון שאין מה משהו אחר ממצביעים‪.‬‬
‫ב‪ Python-‬כל משתנה הוא מצביע‪ ,‬והשמה היא העתקה של המצביע‪ ,‬ולא התוכן )למעט מספרים ומחרוזות(‪.‬‬
‫כאשר מעבירים פרמטרים לפונקציה‪ ,‬הדבר עובד באותה הצורה – שינוי של פרמטר שיועבר לפונקציה הוא שינוי‬
‫המשתנה המקורי שהועבר לפונקציה‪.‬‬

‫תכונה זו מאוד נוחה‪ ,‬אבל לפעמים נרצה ליצור עותק של משתנה קיים – מה נעשה אז? השיטה הכי טובה היא‬
‫להשתמש ב‪ Slicing-‬אותו למדנו מקודם‪ ,‬ובו ראינו שכאשר עושים ‪ Slicing‬שכולל את כל האיברים )בלי ציון התחלה ובלי‬
‫ציון סוף(‪ ,‬נוצר עותק חדש של העצם המקורי‪ .‬כעת נראה איך תתבצע ההשמה עם ‪:Slicing‬‬

‫>>>‬ ‫]‪x = [1, 2, 3‬‬


‫>>>‬ ‫]‪y = x[:‬‬
‫>>>‬ ‫)‪y.append(4‬‬
‫>>>‬ ‫‪x‬‬
‫‪[1,‬‬ ‫]‪2, 3‬‬
‫>>>‬ ‫‪y‬‬
‫‪[1,‬‬ ‫]‪2, 3, 4‬‬

‫יש לציין שה‪ Slicing-‬יעבוד עבור מחרוזות‪ ,‬רשימות‪-Tuple ,‬ים‪ ,‬וכל טיפוס סדרתי‪.‬‬

‫‪Tuples‬‬
‫‪ Tuple‬הוא טיפוס של רשימה קבועה‪ .‬הטיפוס נועד לשימוש במצבים בהם אין אפשרות ליצור רשימה‪ ,‬או כאשר יש צורך‬
‫ברשימה שאורכה לא משתנה‪ .‬כמו כן‪ ,‬לא ניתן לשנות אף אחד מהאיברים ב‪.Tuple-‬‬

‫יצירת ‪ Tuple‬נעשית בדיוק כמו יצירת רשימה‪ ,‬רק שבמקום סוגריים מרובעות משתמשים בסוגריים עגולות‪:‬‬

‫)‪>>> t = (1, 2, 3‬‬


‫‪>>> t‬‬
‫)‪(1, 2, 3‬‬

‫קבלת איבר מה‪ Tuple-‬היא כמו איבר מרשימה – ע"י סוגריים מרובעות‪:‬‬

‫]‪>>> t[0‬‬
‫‪1‬‬

‫אבל אם ננסה לשנות איבר ברשימה‪ ,‬לא יהיה ניתן לעשות זאת‪:‬‬

‫‪>>> t[0] = 2‬‬


‫‪Traceback (most recent call last):‬‬
‫>‪File "<stdin>", line 1, in <module‬‬
‫‪TypeError: object doesn't support item assignment‬‬

‫כמו כן‪ ,‬ניתן לחבר שני ‪-Tuple‬ים‪ .‬התוצאה תהיה ‪ Tuple‬חדש‪:‬‬

‫>>>‬ ‫‪t1‬‬ ‫)‪= (1, 2, 3‬‬


‫>>>‬ ‫‪t2‬‬ ‫)‪= (4, 5, 6‬‬
‫>>>‬ ‫‪t1‬‬ ‫‪+ t2‬‬
‫‪(1,‬‬ ‫‪2,‬‬ ‫)‪3, 4, 5, 6‬‬

‫עמוד ‪14‬‬
‫‪Python 2.5‬‬

‫צריך לדעת שלא ניתן לחבר ‪ Tuple‬לרשימה‪ ,‬משום שהם אינם טיפוסים מאותו הסוג‪.‬‬
‫בנוסף לחיבור‪ ,‬ניתן לעשות ‪ Slicing‬על ‪:Tuple‬‬

‫)‪>>> t = (1, 2, 3, 4, 5‬‬


‫]‪>>> t[1:4‬‬
‫)‪(2, 3, 4‬‬

‫ובדומה לרשימה‪ ,‬השמת ‪ Tuple‬לא תיצור עותק שלו אלא תעביר מצביע‪ .‬ליצירת עותק יש להשתמש ב‪.Slicing-‬‬

‫‪ – Tuple Assignments‬כאשר מבצעים השמה בין שני ‪-Tuple‬ים‪ Python ,‬מבצעת השמה בין כל שני איברים מתאימים ב‪-‬‬
‫‪-Tuple‬ים‪ .‬לדוגמה‪:‬‬

‫>>>‬ ‫)‪(a, b, c) = (1, 2, 3‬‬


‫>>>‬ ‫‪a‬‬
‫‪1‬‬
‫>>>‬ ‫‪b‬‬
‫‪2‬‬
‫>>>‬ ‫‪c‬‬
‫‪3‬‬

‫בדוגמה האחרונה נוצרו שני ‪-Tuple‬ים – באחד שלושה משתנים‪ ,‬ובשני שלושה ערכים‪ Python .‬עשתה השמה בין ‪ a‬ל‪,1-‬‬
‫בין ‪ b‬ל‪ 2-‬ובין ‪ c‬ל‪ .3-‬בצורה כזו‪ ,‬נוצרו שלושה משתנים עם שלושה ערכים התחלתיים בשורה אחת‪ .‬כמובן‪ ,‬לא ניתן‬
‫לבצע השמה בין שני ‪-Tuple‬ים שמכילים "סתם" איברים שלא ניתן להשם ביניהם‪:‬‬

‫)‪>>> (1, 2, 3) = (1, 2, 3‬‬


‫‪SyntaxError: can't assign to literal‬‬

‫אחד הטריקים שניתן לבצע בעזרת ‪ Tuple Assignments‬הוא החלפת ערכי שני משתנים בשורה אחת‪:‬‬

‫‪>>> x, y = y, x‬‬

‫השורה האחרונה פשוט החליפה בין הערכים של ‪ x‬ו‪ ,y-‬ללא צורך במשתנה זמני‪.‬‬

‫השימוש העיקרי ב‪-Tuple-‬ים ב‪ Python-‬הוא עבור אחסון מידע שאין צורך לשנותו )או שיש צורך לוודא שהוא לא ישתנה(‪.‬‬
‫כמו כן‪ ,‬בהמשך החוברת נראה שפונקציה יכולה להחזיר רק איבר אחד‪ .‬משום ש‪ Tuple-‬הוא טיפוס‪ ,‬ניתן להחזיר‬
‫מפונקציה ‪ Tuple‬המכיל מספר איברים‪ ,‬וע"י כך להחזיר יותר מאיבר אחד מפונקציה‪.‬‬

‫מילונים‬
‫מילון )‪ (Dictionary‬ב‪ Python-‬הוא טיפוס שמטרתו היא המרה בין מפתחות לבין ערכים )ב‪ C++-‬משתמשים ב‪ map-‬לכך(‪.‬‬
‫מילון למעשה מחזיק ערכים‪ ,‬מפתחות ואת המיפוי ביניהם‪ .‬כאשר המשתמש פונה למילון‪ ,‬הוא מציין מפתח‪ ,‬ומקבל‬
‫עבורו ערך‪ .‬היתרון בכך הוא שבמקום מספרי אינדקסים )שלא ממש אומרים משהו למישהו(‪ ,‬ניתן להשתמש בכל ערך‬
‫שרק רוצים‪ ,‬אפילו מחרוזות‪.‬‬

‫יצירת מילון נעשית כמו רשימה‪ ,‬אבל עם סוגריים מסולסלות‪:‬‬

‫}{ = ‪>>> d‬‬

‫כעת נוסיף למילון ‪ d‬את המיפוי בין המפתח ‪ 1‬למחרוזת ”‪:“Sunday‬‬

‫”‪>>> d[1] = “Sunday‬‬


‫‪>>> d‬‬
‫}'‪{1: 'Sunday‬‬

‫כעת המילון ‪ d‬יודע שה"ערך" של ‪ 1‬הוא "‪ ."Sunday‬בקשת ערך עבור מפתח מסוים נעשית כמו ברשימה‪:‬‬

‫]‪>>> d[1‬‬
‫'‪'Sunday‬‬

‫כמו כן‪ ,‬ניתן ליצור מפתחות שאינם מספרים‪ .‬למשל‪ ,‬ניצור מילון שממיר בין מדינה לבירה שלה‪:‬‬

‫>>>‬ ‫}{ = ‪cap‬‬


‫>>>‬ ‫'‪cap['Israel'] = 'Jerusalem‬‬
‫>>>‬ ‫'‪cap['USA'] = 'Washington‬‬
‫>>>‬ ‫'‪cap['Russia'] = 'Moscow‬‬
‫>>>‬ ‫'‪cap['France'] = 'Paris‬‬
‫>>>‬ ‫'‪cap['England'] = 'London‬‬
‫>>>‬ ‫'‪cap['Italy'] = 'Rome‬‬
‫עמוד ‪15‬‬
‫‪Python 2.5‬‬

‫בעת פנייה למילון נוכל לציין מייד את שם המדינה ולקבל את הבירה שלה‪:‬‬

‫]'‪>>> cap['France‬‬
‫'‪'Paris‬‬

‫אם נפנה למפתח שאינו קיים‪ ,‬תוחזר שגיאה‪:‬‬

‫]'‪>>> cap['Japan‬‬
‫‪Traceback (most recent call last):‬‬
‫>‪File "<stdin>", line 1, in <module‬‬
‫‪KeyError: Japan‬‬

‫בנוסף לפעולות ההמרה‪ ,‬ניתן לבדוק גם האם מפתח מסוים קיים במילון‪ ,‬בעזרת האופרטור ‪:in‬‬

‫‪>>> ‘Japan’ in cap‬‬


‫‪False‬‬
‫‪>>> ‘Israel’ in cap‬‬
‫‪True‬‬
‫‪ keys‬היא פונקציה שמחזירה את רשימת המפתחות במילון‪:‬‬

‫)(‪>>> cap.keys‬‬
‫]'‪['Israel', 'Italy', 'USA', 'England', 'Russia', 'France‬‬

‫‪ values‬היא פונקציה שמחזירה את רשימת הערכים במילון‪:‬‬

‫)(‪>>> cap.values‬‬
‫]'‪['Jerusalem', 'Rome', 'Washington', 'London', 'Moscow', 'Paris‬‬

‫עמוד ‪16‬‬
‫‪Python 2.5‬‬

‫פרק ‪_:4‬בקרת זרימה‬


‫‪if‬‬
‫‪ if‬היא כמובן פקודת ההתניה )‪ ,(Conditioning‬כמו ברוב שפות התכנות‪ .‬מבנה הפקודה דומה לזה שבשפת ‪ C‬מלבד‬
‫העובדה שאין חובה בסוגריים‪ .‬דוגמה די פשוטה ל‪:if-‬‬

‫‪num = 5‬‬
‫‪if num > 3:‬‬
‫‪print num * 2‬‬

‫בשורה הראשונה יצרנו משתנה בשם ‪ num‬שערכו ‪ .5‬השורה השניה היא שורת ה‪ if-‬עצמה‪ ,‬ומבנה ההתניה דומה לזה‬
‫שב‪) C-‬מיד נראה מספר הבדלים(‪ .‬בסוף השורה השניה יש נקודותים‪ .‬תו ה‪ ':'-‬ב‪ Python-‬מורה על פתיחת בלוק חדש‪,‬‬
‫בדיוק כמו הסוגריים‪-‬המסולסלות ב‪.C-‬‬
‫ואיך ‪ Python‬יודעת מתי בלוק נגמר? את זה היא עושה באמצעות תו ה‪ .TAB-‬בדוגמה למעלה‪ ,‬השורה השלישית מוזחת‬
‫ימינה ב‪ TAB-‬אחד‪ ,‬ולא סתם בשביל אינדנטציה )כמו ב‪ .(C-‬האינדנטציה )‪ ,Indentation‬הפעולה בה בלוק שתלוי בבלוק‬
‫קודם ייכתב "פנימה" יותר בקוד‪ ,‬במקרה הזה ימינה ב‪ TAB-‬אחד( ב‪ Python-‬היא חלק מהמבנה שלה‪ ,‬ולכן אי‪-‬אפשר‬
‫לכתוב בלי להוסיף ‪ TAB‬לפני כל שורה בבלוק‪.‬‬

‫דבר נוסף‪ ,‬חשוב לשים את תו ה‪ ,(‘\t’) TAB-‬ולא שום אלתור אחר‪ ,‬כמו ‪ 4‬או ‪ 5‬רווחים‪ Python .‬מחפש את תו ה‪,TAB-‬‬
‫וצריך להיזהר מלשכוח לשים אותו – אפשר לשבת שעות מול שגיאה שנראית לכאורה בקוד ולגלות בסוף ששכחת‬
‫לשים ‪ .TAB‬כמו כן‪ ,‬ישנם עורכי טקסט שממירים ‪ TAB‬למספר רווחים‪ ,‬או עושים דברים יותר משונים‪ .‬לכן עדיף‬
‫להשתמש בעורכים שאפשר לסמוך עליהם שלא יתעללו בקוד )כמו ‪ .(vi ,EditPlus ,Notepad‬יש לציין שכותבי ה‬
‫‪ Interpreter‬בנו אותו בצורה יחסית אמינה‪ ,‬שמסוגלת להתמודד גם עם רווחים בחלק מהמקרים‪ .‬בכל אופן ‪ -‬כדאי לא‬
‫לבדוק את היכולת הזו וללכת על בטוח‪.‬‬
‫בנוסף לתנאים רגילים‪ ,‬אפשר כמובן ליצור תנאים לוגיים‪ .‬ב‪ Python-‬קיימות מילות המפתח ‪ or ,and‬ו‪ ,not-‬בנוסף‬
‫לאופרטורים הלוגיים שלקוחים מ‪ .C-‬השימוש הוא די פשוט‪:‬‬

‫‪num = 17‬‬
‫‪if (num > 5) or (num == 15):‬‬
‫”‪print “something‬‬

‫השימוש הוא זהה עבור ‪ not .and‬יכול לבוא לפני תנאי כדי להפוך אותו‪:‬‬

‫‪if not 4 == 7:‬‬


‫”‪print “always true‬‬

‫‪while‬‬
‫פקודת הלולאה ‪ while‬מאפשרת חזרה על פקודות על עוד תנאי מסוים מתקיים‪ .‬התנאי יכול להיכתב כמו תנאי ב‪.if-‬‬
‫דוגמה‪:‬‬

‫‪i = 0‬‬
‫‪while i < 10:‬‬
‫‪print i‬‬
‫‪i += 1‬‬

‫בפקודת ‪ while‬ב‪ Python-‬קיים גם משפט ‪ .else‬משפט זה מתבצע במקרה ובו התנאי שניתן לביצוע הלולאה לא התקיים‬
‫אפילו פעם אחת‪ ,‬ולא הייתה שום כניסה לגוף הלולאה‪:‬‬

‫‪>>> i = 40‬‬
‫‪>>> while i > 50:‬‬
‫‪...‬‬ ‫‪i -= 1‬‬
‫‪...‬‬ ‫‪print i‬‬
‫‪... else:‬‬
‫‪...‬‬ ‫'!‪print 'i is smaller than 50‬‬
‫‪...‬‬
‫!‪i is smaller than 50‬‬

‫‪for‬‬
‫לפני שנסקור את פקודת ‪ ,for‬נגדיר מהו רצף – רצף הוא עצם שמכיל בתוכו איברים‪ ,‬בסדר מסוים‪ ,‬כאשר העצם מכיל‬
‫פונקציות לקבלת כל‪-‬אחד מהאיברים )או פונקציות לקבלת איבר ראשון ואיבר עוקב לאיבר קיים(‪.‬‬
‫דוגמאות לרצפים שאנחנו כבר מכירים ב‪ Python-‬הן רשימות‪Tuple ,‬ים‪ ,‬מחרוזות ומילונים‪.‬‬

‫פקודת הלולאה ‪ for‬שונה מזו שב‪ for .C-‬ב‪ Python-‬לא מבצעת לולאה על תחום ערכים )כמו ב‪ (Pascal-‬או מאחדת בתוכה‬
‫משפט‪-‬אתחול‪ ,‬תנאי ופקודה לביצוע בכל איטרציה )כמו ב‪.(C-‬‬

‫עמוד ‪17‬‬
‫‪Python 2.5‬‬

‫‪ for‬ב‪ Python-‬מקבלת רצף )כלומר אוסף של איברים(‪ ,‬ובכל איטרציה מתייחסת רק לאיבר אחד ברצף‪ .‬ההתייחסות‬
‫לאיברים נעשית לפי הסדר בו הם מאוחסנים ברצף‪ ,‬כאשר הסדר נקבע לפי טיפוס הנתונים הנתון )אף אחד לא מבטיח‬
‫סדר מסוים‪ ,‬אלא אם כן זוהי אחת מהגדרותיו של טיפוס הנתונים(‪.‬‬

‫דוגמה פשוטה ל‪:for-‬‬

‫)’‪days = (‘Sun’, ‘Mon’, ‘Tue’, ‘Wed’, ‘Thu’, ‘Fri’, ‘Sat‬‬


‫‪for day in days:‬‬
‫‪print day‬‬

‫בדוגמה‪ ,‬הלולאה יצרה משתנה בשם ‪ .day‬בכל איטרציה‪ day ,‬מקבל את האיבר הבא של ‪ .days‬הפלט של הריצה יהיה‪:‬‬

‫‪Sun‬‬
‫‪Mon‬‬
‫‪Tue‬‬
‫‪Wed‬‬
‫‪Thu‬‬
‫‪Fri‬‬
‫‪Sat‬‬

‫חשוב לציין שבסיום ריצת הלולאה‪ ,‬המשתנה ‪ day‬ימשיך להתקיים‪ ,‬וערכו יהיה הערך האחרון שקיבל במהלך ריצת‬
‫הלולאה‪.‬‬
‫אם מריצים לולאת ‪ for‬עם רשימה ריקה‪ ,‬כלום לא יקרה והמשתנה ‪) day‬או כל משתנה אחר שייכתב שם( לא ייווצר‪ .‬יש‬
‫לשים לב שאם מריצים כמה לולאות‪ ,‬אחת אחרי השניה‪ ,‬עם אותו משתנה )נגיד ‪ ,(i‬ובאחת הלולאות יש רשימה ריקה‪,‬‬
‫אין הדבר אומר שהמשתנה ‪ i‬יושמד‪ .‬זה רק אומר שהוא לא ישתנה עקב הלולאה הזו‪ .‬אם הלולאה הזו היא הלולאה‬
‫הראשונה‪ i ,‬באמת לא ייווצר‪:‬‬

‫>>>‬ ‫‪for i in xrange(5):‬‬


‫‪...‬‬ ‫‪print i‬‬
‫‪0‬‬
‫‪1‬‬
‫‪2‬‬
‫‪3‬‬
‫‪4‬‬
‫>>>‬ ‫‪i‬‬
‫‪4‬‬
‫>>>‬ ‫‪for i in xrange(0):‬‬
‫‪...‬‬ ‫‪print i‬‬
‫>>>‬ ‫‪i‬‬
‫‪4‬‬

‫כאמור‪ ,‬ניתן לעבור לא רק על רשימות‪ ,‬אלא גם על מילונים ומחרוזות‪ .‬להלן שתי דוגמאות להמחשת העבודה עם‬
‫מחרוזות ומילונים‪:‬‬

‫>>>‬ ‫}{ = ‪dic‬‬


‫>>>‬ ‫‪dic[1] = 10‬‬
‫>>>‬ ‫‪dic[2] = 20‬‬
‫>>>‬ ‫‪dic[3] = 30‬‬
‫>>>‬ ‫‪dic[4] = 40‬‬
‫>>>‬ ‫‪dic[5] = 50‬‬
‫>>>‬ ‫‪for i in dic:‬‬
‫‪...‬‬ ‫‪print i‬‬
‫‪...‬‬
‫‪1‬‬
‫‪2‬‬
‫‪3‬‬
‫‪4‬‬
‫‪5‬‬
‫>>>‬ ‫'‪str = 'Yet another string‬‬
‫>>>‬ ‫‪for char in str:‬‬
‫‪...‬‬ ‫‪print char‬‬
‫‪...‬‬
‫‪Y‬‬
‫‪e‬‬
‫‪t‬‬

‫‪a‬‬
‫‪n‬‬

‫עמוד ‪18‬‬
‫‪Python 2.5‬‬

‫‪o‬‬
‫‪t‬‬
‫‪h‬‬
‫‪e‬‬
‫‪r‬‬

‫‪s‬‬
‫‪t‬‬
‫‪r‬‬
‫‪i‬‬
‫‪n‬‬
‫‪g‬‬

‫הערה לגבי מילונים – בהגדרת המילון לא נאמר שהסדר בו האיברים מופיעים בו הוא הסדר בו הם יאוחסנו או הסדר בו‬
‫הם יוחזרו בלולאת ‪ .for‬לכן‪ ,‬אין להניח הנחות על סדר האיברים בטיפוס מסוים‪ ,‬אלא אם נאמר אחרת בהדגרת הטיפוס‪.‬‬
‫הנחה שכן ניתן להניח )וגם זאת בזהירות רבה מאוד( היא שאם הרצנו לולאת ‪ for‬על רשימה מסוימת‪ ,‬והרשימה לא‬
‫השתנתה‪ ,‬ריצת ‪ for‬נוספת על אותה הרשימה תתבצע באותו הסדר‪.‬‬

‫‪range, xrange‬‬
‫טוב‪ ,‬אז יש לולאת ‪ for‬שיודעת לעבור על כל האיברים ברשימה‪ .‬אבל מה אם כן רוצים לעשות לולאת ‪ for‬כמו ב‪ ,C-‬אבל‬
‫לא רוצים להשתמש ב‪.while-‬‬
‫פתרון אחד )לא מומלץ( הוא ליצור רשימה שמכילה את כל המספרים שנרצה לעבור עליהם‪ ,‬מ‪ 0-‬עד ‪ .X‬ברור שפתרון‬
‫זה לא טוב‪ ,‬אם ‪ X‬משתנה מריצה לריצה‪ ,‬או אם הוא מאוד גדול‪.‬‬
‫‪ Python‬פותרת עבורנו את הבעיה באמצעות הפונקציות המובנות ‪ range‬ו‪ .xrange-‬שתי הפונקציות עושות את אותו‬
‫הדבר‪ ,‬אבל בצורה שונה‪ range .‬יוצרת רשימה חדשה אם ערך התחלתי‪ ,‬ערך סופי וקפיצה )‪ ,Step‬ההפרש בין כ"א‬
‫מהאיברים(‪.‬‬
‫מבנה הפונקציה ‪:range‬‬

‫)]‪range([start], end, [step‬‬

‫‪ – start‬זהו פרמטר אופציונלי‪ ,‬ומציין את ערך ההתחלה )כולל( של הרשימה‪.‬‬


‫‪ – end‬ערך זה תמיד ייכלל ב‪ range-‬ומציין את הערך האחרון ברשימה )לא כולל(‪ .‬כלומר‪ ,‬הרשימה מגיעה עד הערך‬
‫הזה‪ ,‬ולא כוללת אותו‪.‬‬
‫‪ – step‬ההפרש בין כל שני איברים סמוכים ברשימה‪ .‬כמובן‪ ,‬הפרש זה חייב להיות גדול מאפס‪.‬‬
‫דוגמאות ל‪:range-‬‬

‫‪>>> for i in range(10):‬‬


‫‪...‬‬ ‫‪print i‬‬
‫‪0‬‬
‫‪1‬‬
‫‪2‬‬
‫‪3‬‬
‫‪4‬‬
‫‪5‬‬
‫‪6‬‬
‫‪7‬‬
‫‪8‬‬
‫‪9‬‬
‫‪>>> for i in range(2, 10, 2):‬‬
‫‪...‬‬ ‫‪print i‬‬
‫‪2‬‬
‫‪4‬‬
‫‪6‬‬
‫‪8‬‬

‫כלומר‪ range ,‬יוצרת רשימה חדשה עבורנו‪ .‬הרשימה יכולה למעשה להכיל כל סדרה חשבונית שהיא‪.‬‬
‫כמו כן‪ ,‬ניתן לקחת את הרשימה שנוצרה ולהצביע אליה עם משתנה‪ ,‬ואז נקבל רשימה חדשה בממש מעט קוד‪:‬‬

‫)‪k = range(1024‬‬

‫אז בשביל מה יש ‪?xrange‬‬


‫‪ xrange‬לא יוצרת עבורנו רשימה‪ ,‬אלא יוצרת אובייקט רצף‪ ,‬שניתן לקבל ממנו התחלה‪ ,‬סוף ואת האיבר הבא לאיבר‬
‫קיים‪ .‬בצורה כזו‪ ,‬אובייקט ‪ xrange‬מחזיק את תחום הערכים אותו הוא צריך להחזיר ואת ההפרש בין כל שני איברים‪ .‬בכל‬
‫קריאה לקבלת האיבר הבא‪ ,‬האובייקט מחשב את האיבר הבא במקום לאחסן אותו בזיכרון‪ .‬כאשר מבקשים את האיבר‬
‫הבא לאיבר האחרון‪ ,‬אובייקט ה‪ xrange-‬מודיע על סוף הרשימה‪.‬‬
‫הסיבה שנרצה בכלל להשתמש ב‪ xrange-‬היא שעצם יצירת רשימה חדשה‪ ,‬רק עבור הלולאה‪ ,‬ולא כדי להשתמש בה‬
‫מאוחר יותר‪ ,‬היא שיצירת רשימה לוקחת זיכרון‪ ,‬ואם נשתמש ב‪ range-‬עם תחום ערכים גדול‪ ,‬סתם נבזבז זיכרון‪.‬‬

‫עמוד ‪19‬‬
‫‪Python 2.5‬‬

‫לעומת זאת‪ ,‬מבחינת ביצועים‪ range ,‬יותר יעילה מ‪ ,xrange-‬משום שבעת קבלת האיברים מהרשימה‪ xrange ,‬צריכה‬
‫לחשב את האיבר הבא בכל פעם‪ ,‬בעוד ‪ range‬מחזירה רשימה מוכנה לשימוש‪ ,‬וצריך רק להחזיר ממנה את האיבר הבא‬
‫)ואין צורך לחשב אותו(‪ .‬השימוש בכל‪-‬אחת מהפונקציות תלוי במקרה בו משתמשים בהן‪ ,‬והאם יש עדיפות לחיסכון‬
‫בזיכרון או לשיפור בביצועים‪.‬‬
‫המבנה של ‪ xrange‬זהה לזה של ‪.range‬‬

‫‪break, continue‬‬
‫משפט ‪ break‬נועד ליציאה מלולאות ‪ for‬או ‪ break .while‬יוצא רק מבלוק ה‪ for-‬או בלוק ה‪ while-‬בו הוא נמצא‪ ,‬ולא מסוגל‬
‫לצאת החוצה יותר מבלוק אחד‪.‬‬
‫משפט ‪ continue‬מורה להפסיק מיד את האיטרציה הנוכחית של הלולאה ולהתחיל את האיטרציה הבאה‪ .‬כמו ‪ ,break‬גם‬
‫‪ continue‬יכול לצאת רק מבלוק הלולאה הקרוב אליו‪.‬‬
‫דוגמאות‪:‬‬

‫‪>>> for monty in xrange(5):‬‬


‫‪...‬‬ ‫‪for python in xrange(5):‬‬
‫‪...‬‬ ‫‪continue‬‬
‫‪...‬‬ ‫‪print monty * python‬‬
‫‪0‬‬
‫‪4‬‬
‫‪8‬‬
‫‪12‬‬
‫‪16‬‬
‫‪pass‬‬
‫משפט אחרון חביב לפרק זה הוא ‪ – pass‬המשפט שאומר לא לעשות כלום )כן‪ ,‬יש כזה דבר(‪.‬‬
‫הסיבה לכך שיש כזה משפט בכלל היא לא בשביל שאפשר יהיה לכתוב את המשפט הזה בכל מני מקומות בקוד כדי‬
‫שיהיו יותר שורות )בכלל‪ ,‬אי אפשר לרשום אותו בכל מקום(‪.‬‬
‫משפט זה משמש כחלק מבקרת הזרימה‪ :‬לפעמים אנחנו רושמים לולאה‪ ,‬כי אנחנו יודעים שהיא צריכה להיות במקום‬
‫מסוים בקוד‪ ,‬אבל אנחנו לא ממש רוצים לכתוב אותה כרגע‪ ,‬אין לנו איך‪ ,‬או ‪ (9) 1001‬סיבות אחרות‪.‬‬
‫בגלל ש‪ Python-‬מחפשת את תו ה‪ TAB-‬בבלוק חדש‪ ,‬זאת תהיה שגיאה לא לפתוח בלוק במקומות מסוימים‪ .‬כמו כן‪,‬‬
‫זאת שגיאה לשים סתם שורה ריקה עם ‪ TAB‬בהתחלה‪.‬‬
‫לכן‪ ,‬ניתן לרשום במקום הבלוק החסר את המשפט ‪ ,pass‬ו‪ Python-‬פשוט תעבור הלאה את הלולאה‪:‬‬

‫‪>>> for k in xrange(0, 500, 5):‬‬


‫‪...‬‬ ‫‪pass‬‬

‫עמוד ‪20‬‬
‫‪Python 2.5‬‬

‫פרק ‪_:5‬קלט ופלט‬


‫הדפסה למסך‬
‫הדפסה למסך נעשית באמצעות הפקודה המובנית ‪:print‬‬

‫’‪>>> print ‘Hello‬‬


‫‪Hello‬‬

‫הפקודה יכולה לקבל פרמטר אחד )כמו בדוגמה האחרונה( או מספר פרמטרים מופרדים בפסיקים‪:‬‬

‫‪>>> print ‘Hello World!’, ‘My age is’, 17‬‬


‫‪Hello World! My age is 17‬‬

‫כפי שניתן לראות‪ print ,‬מוסיפה אוטומטית רווחים בין הפרמטרים שנשלחים להדפסה‪ .‬כמו כן‪ ,‬ניתן לתת כפרמטר כל‬
‫סוג משתנה‪ ,‬כל עוד ניתן להמיר אותו למחרוזת כדי להדפיס אותו‪.‬‬

‫בנוסף‪ ,‬הפקודה תמיד מדפיסה תו סיום שורה בסופה‪ ,‬אלא אם כן שמים פסיק בסוף השורה‪:‬‬

‫‪>>> for i in range(1):‬‬


‫‪...‬‬ ‫‪print 'look!',‬‬
‫‪...‬‬ ‫'!‪print 'this is the same line‬‬
‫‪...‬‬
‫!‪look! this is the same line‬‬

‫השימוש בלולאת ‪ for‬בדוגמה האחרונה היה כדי ששתי הפקודות יבוצעו אחת אחרי השניה‪ ,‬כי אם נכתוב את הפקודות‬
‫אחרת אחרי השניה ב‪ ,Interpreter-‬ה‪ Interpreter-‬יירד שורה באופן אוטומאטי לאחר כל ביצוע פקודה‪ ,‬כדי לחזור לסמן‬
‫של הכנסת הפקודה הבאה )>>>(‪.‬‬

‫כמו כן‪ ,‬ניתן לתת ל‪ print-‬מחרוזת מפורמטת‪:‬‬

‫‪>>> print ‘His age is %d.’ % 17‬‬


‫‪His age is 17.‬‬

‫קלט מהמקלדת‬
‫כאשר תוכנית מעוניינת לקבל קלט מהמשתמש )דרך המקלדת בד"כ(‪ ,‬ניתן להשתמש בפונקציה המובנית ‪.raw_input‬‬
‫הפונקציה מקבלת כפרמטר מחרוזת אותה היא מדפיסה למסך‪ ,‬ואז היא ממתינה לשורת קלט מהמשתמש‪ .‬הקלט‬
‫יסתיים כאשר המשתמש יקיש על ‪ .Enter‬דוגמה לשימוש ב‪:raw_input-‬‬

‫)’ >‪>>> raw_input(‘--‬‬


‫!‪--> hello world‬‬
‫’!‪‘hello world‬‬

‫ערך ההחזרה של הפונקציה הוא מחרוזת‪.‬‬

‫קבצים‬
‫הטיפול בקבצים ב‪ Python-‬פשוט בהרבה מזה שב‪ .C-‬פונקציות הטיפול בקבצים מובנות‪ ,‬ונקראות ‪ open‬ו‪ .close-‬פתיחת‬
‫קובץ נעשית באופן הבא‪:‬‬

‫)’‪>>> opened_file = open(‘x.dat’, ‘w‬‬

‫כלומר‪ ,‬הפונקציה ‪ open‬מחזירה אובייקט מסוג קובץ‪ ,‬כאשר הפרמטרים לפונקציה הם שם הקובץ וסוג הגישה )’‪‘w‬‬
‫לכתיבה‪ ‘r’ ,‬לקריאה‪ ,‬וכו' כמו ב‪ .(C-‬לאחר מכן ניתן לכתוב לקובץ באמצעות הפונקציה ‪:write‬‬

‫)’‪>>> opened_file.write(‘my first file!\n‬‬


‫)’!‪>>> opened_file.write(‘my second line‬‬

‫בסיום העבודה עם הקובץ יש לסגור אותו באמצעות הפונקציה ‪:close‬‬

‫)(‪>>> file.close‬‬

‫ניתן גם לפתוח קובץ לקריאה ולקרוא ממנו את כל התוכן שלו למשתנה אחד‪:‬‬

‫)’‪>>> file = open(‘x.dat’, ‘r‬‬


‫)(‪>>> content = file.read‬‬

‫עמוד ‪21‬‬
Python 2.5

>>> file.close()

:‫ מכיל את תוכן הקובץ שיצרנו בדוגמה הקודמת‬content ‫כעת המשתנה‬

>>> print content


my first file!
my second line!

22 ‫עמוד‬
‫‪Python 2.5‬‬

‫פרק ‪_:6‬פונקציות‬
‫עד כה עסקנו במשחקים קטנים ונחמדים עם קוד קצר ופשוט‪ .‬אבל‪ ,‬כמו שנאמר במבוא‪ Python ,‬היא שפה מאוד חזקה‪,‬‬
‫עד כדי כך שניתן לכתוב בה אפליקציות שלמות‪.‬‬
‫כמובן‪ ,‬כמו בכל שפה‪ ,‬כתיבת אפליקציות )או סתם תוכניות רגילות( תתבצע ע"י חלוקה לפונקציות‪ ,‬פרוצדורות‪,‬‬
‫מודולים‪ ,‬יחידות ספריה‪ ,‬וכו'‪ .‬פרק זה עוסק בפונקציות‪.‬‬

‫הגדרת פונקציות‬
‫בדומה ל‪ ,C-‬אין הבדל בין פונקציות )‪ (Functions‬לבין פרוצדורות )‪ – (Procedures‬יש פונקציות שמחזירות ערך ויש‬
‫פונקציות שלא‪ .‬בשונה מ‪ ,C-‬פונקציה יכולה להחזיר ערך‪ ,‬לא להחזיר כלום‪ ,‬או להחזיר מספר טיפוסים שונים במקרים‬
‫שונים‪ ,‬וזאת מבלי לשנות את ההגדרה שלה )ה‪ Prototype-‬שלה(‪.‬‬
‫כמו כן‪ ,‬חוקי ה‪ Case Sensitivity-‬זהים לאלו של משתנים – יש הבדל בין אותיות גדולות וקטנות )לדוגמה‪ ,‬פונקציה בשם ‪f‬‬
‫איננה זהה לפונקציה בשם ‪.(F‬‬
‫הגדרת פונקציה פשוטה )בלי פרמטרים(‪:‬‬

‫‪>>> def func():‬‬


‫‪...‬‬ ‫”‪print “I am a function‬‬
‫)(‪>>> func‬‬
‫’‪‘I am a function‬‬

‫הפונקציה הזו לא מקבלת שום פרמטר‪ ,‬וגם לא מחזירה כלום )אין בה משפט ‪ .(return‬אם ניקח את ערך ההחזרה של‬
‫הפונקציה ונשים אותו בתוך משתנה‪ ,‬המשתנה יכיל "כלום"‪:‬‬

‫)(‪>>> h = func‬‬
‫’‪‘I am a function‬‬
‫‪>>> h‬‬
‫>>>‬

‫וכמו שניתן לראות‪ ,‬כלום לא הודפס – המשתנה ‪ h‬מכיל "כלום"‪.‬‬


‫ה‪"-‬כלום" הזה מכונה ב‪ None .“None” Python-‬הוא עצם יחיד )‪ ,(Singleton‬שמצביעים אליו כשרוצים לציין שאין לנו למה‬
‫להצביע‪ None .‬לא אומר שאין לנו מה להחזיר )כמו ב‪ ,(C-‬אלא אומר שאנחנו לא מחזירים כלום )או ליתר דיוק‪ ,‬מחזירים‬
‫"כלום"(‪ .‬כמו כן‪ None ,‬הוא ערך חוקי לכל דבר‪ ,‬וניתן להשים אותו למשתנים באותו האופן שניתן להחזיר אותו‬
‫מפונקציות‪.‬‬
‫על‪-‬מנת שפונקציה תחזיר ‪ ,None‬ניתן לעשות שלושה דברים‪:‬‬
‫‪ .1‬לא לרשום שום משפט ‪.return‬‬
‫‪ .2‬לרשום שורה ובה המילה ‪ return‬בלבד‪.‬‬
‫‪ .3‬לרשום את המשפט ‪.return None‬‬

‫‪ pass‬בפונקציות‬
‫כמו בלולאות‪ pass ,‬עובד יפה מאוד גם בפונקציות‪ .‬פשוט רושמים ‪ pass‬במקום בלוק הפונקציה‪:‬‬

‫‪def doing_nothing():‬‬
‫‪pass‬‬

‫פרמטרים‬
‫העברת הפרמטרים לפונקציות ב‪ Python-‬מאחדת למעשה את הנוחות של משתנים ב‪ Python-‬עם אפשרות ה‪Default -‬‬
‫‪ Value‬של ‪ .C++‬העברת פרמטרים תיעשה בסוגריים של הפונקציה‪:‬‬

‫‪def func_with_args(a, b, c):‬‬


‫‪pass‬‬

‫לפונקציה זו העברנו שלושה פרמטרים‪ ,b ,a :‬ו‪ .c-‬כמו שניתן לראות‪ ,‬אין צורך בטיפוס‪ ,‬כי ב‪ Python-‬משתנה יכול להיות‬
‫מכל טיפוס שהוא‪ .‬כמובן‪ ,‬זה לא אומר שניתן להעביר כל סוג משתנה שהוא לפונקציה‪ ,‬הרי היא מצפה לסוג משתנה‬
‫מסוים‪ .‬אם לא נוהגים בחופש זה בזהירות‪ ,‬ניתן לגרום לכל תוכנית פשוטה לקרוס ממש מהר‪.‬‬
‫הפרמטרים שמועברים לפונקציה מועברים אליה ‪ ,By Value‬כלומר נוצר עותק של המשתנה עבור הפונקציה‪ ,‬והמשתנים‬
‫מצביעים לעותק זה‪ .‬כמובן שעבור רצפים )רשימות וכו'( אין משמעות לעותק הנ"ל‪ ,‬כיוון שהוא מצביע לאותו אובייקט‪.‬‬
‫בעת היציאה מהפונקציה‪ ,‬יושמדו העותקים האלה )אלא אם כן הם יוחזרו ע"י הפונקציה‪ ,‬ואז יכול להיווצר עותק עבור‬
‫ערך ההחזרה‪ ,‬או שיוחזר העותק המקורי של הפונקציה – תלוי במימוש(‪.‬‬
‫ניתן לציין ערכי ‪ Default‬לפרמטרים‪ .‬החוקים לזה דומים לאלה שב‪ :C++-‬המשתנים בעלי ערך ‪ Default‬חייבים להופיע‬
‫כפרמטרים האחרונים )אי‪-‬אפשר שאחרי פרמטר בעל ערך ‪ Default‬יופיע פרמטר בלי ערך ‪ .(Default‬כמו כן‪ ,‬בעת‬
‫הקריאה לפונקציה‪ ,‬אי‪-‬אפשר להשאיר "פרמטרים ריקים" )כלומר‪ ,‬לשים פסיק כדי לדלג על משתנה‪ ,‬בניגוד ל‪,BASIC-‬‬
‫בה מותר לעשות דבר כזה(‪ ,‬וחובה להעביר את כל הפרמטרים לפונקציה‪.‬‬

‫כמובן‪ ,‬דוגמה‪:‬‬
‫עמוד ‪23‬‬
‫‪Python 2.5‬‬

‫>>>‬ ‫‪def func_with_defaults(x, y=5, z=17):‬‬


‫‪...‬‬ ‫‪print x, y, z‬‬
‫>>>‬ ‫)‪func_with_defaults(1‬‬
‫‪1 5‬‬ ‫‪17‬‬
‫>>>‬ ‫)‪func_with_defaults(1,4‬‬
‫‪1 4‬‬ ‫‪17‬‬
‫>>>‬ ‫)‪func_with_defaults(9,8,5‬‬
‫‪9 8‬‬ ‫‪5‬‬

‫וכאמור‪ ,‬אי‪-‬אפשר לרשום מוטציות מוזרות כמו‪:‬‬

‫)‪>>> func_with_defaults(1,,9‬‬
‫‪File “<stdin”>, line 1‬‬
‫)‪func(1,,9‬‬
‫‪SyntaxError: invalid syntax.‬‬

‫עם זאת‪ ,‬נוכל "לדלג" על פרמטרים בעלי ערך מוגדר מראש‪ ,‬ולהעביר רק את הפרמטרים שנרצה בצורה מפורשת‪:‬‬

‫)‪>>> func_with_defaults(1, z=9‬‬


‫‪1 5 9‬‬

‫עכשיו‪ ,‬הדבר היחיד שחסר לנו כדי להשלים את כל התכונות של פונקציות ב‪ C-‬ו‪ C++-‬הוא ה‪) Ellipsis-‬כאשר שמים ‪...‬‬
‫בסוף שורת הארגומנטים לפונקציה כדי להעביר מספר לא ידוע של פרמטרים‪ ,‬כמו ב‪ .(printf()-‬דבר זה ממומש ב‪-‬‬
‫‪ Python‬בצורה הרבה יפה מאשר ב‪ :C-‬כאשר רוצים שפונקציה תקבל מספר לא ידוע של פרמטרים‪ ,‬פשוט מוסיפים עוד‬
‫פרמטר אחד בסופה‪ .‬לפני שם הפרמטר שמים כוכבית‪ ,‬וזה אומר ל‪ Python-‬לקחת את כל הפרמטרים שיתווספו אחרי‬
‫הפרמטרים הרגילים ולהפוך אותם ל‪ .Tuple-‬אחרי זה‪ ,‬העבודה מול ‪ Tuple‬היא כבר נוחה ופשוטה‪.‬‬

‫‪>>> def iddqd_idkfa(x, *t):‬‬


‫‪...‬‬ ‫‪print x‬‬
‫‪...‬‬ ‫‪print t‬‬
‫)‪>>> iddqd_idkfa(1, 2, 3, 4, 5‬‬
‫‪1‬‬
‫)‪(2, 3, 4, 5‬‬

‫בעיה קטנטנה שמתעוררת כאן היא כאשר יש לנו שתי פונקציות‪ ,‬ושתיהן מקבלות "‪ "Ellipsis‬כזה בסופן‪ .‬מה יקרה כאשר‬
‫קראו לפונקציה אחת‪ ,‬והיא רוצה להעביר את כל רשימת הפרמטרים לפונקציה השניה‪ ,‬אבל לא כ‪ ,Tuple-‬אלא כרשימה‬
‫אמיתית‪ ,‬כאילו קראו לה עם רשימת הפרמטרים?‬
‫רק כדי להמחיש את הבעיה‪ ,‬הנה שתי הפונקציות‪:‬‬

‫‪>>> def yanti(x, *y):‬‬


‫‪...‬‬ ‫‪print x ,y‬‬
‫‪...‬‬ ‫)‪parazi(x, y‬‬
‫‪...‬‬
‫‪>>> def parazi(x, *y):‬‬
‫‪...‬‬ ‫‪print x, y‬‬
‫‪...‬‬

‫הנה מה שיקרה כאשר נקרא ל‪:yanti-‬‬

‫)‪>>> yanti(1, 2, 3‬‬


‫)‪1 (2, 3‬‬
‫) ‪1 ((2, 3),‬‬

‫מה שקרה כאן הוא שבעת הקריאה ל‪ Python ,yanti-‬המירה את הפרמטרים העודפים ל‪ ,Tuple-‬אליו מצביע הפרמטר ‪.y‬‬
‫כאשר ‪ yanti‬קראה ל‪ ,parazi-‬היא העבירה )כפרמטר עודף אחד!( את כל ה‪ ,Tuple-‬כי ה‪ Tuple-‬הוא הרי טיפוס‪ ,‬משתנה‬
‫אחד‪ ,‬בדיוק כמו מספר שלם או מחרוזת‪.‬‬
‫‪ parazi‬קיבלה את ה‪ Tuple-‬כפרמטר אחד‪ ,‬לקחה את הפרמטר והכניסה אותו ל‪ Tuple-‬שלה‪ ,‬אותו היא יוצרת עבור‬
‫הפרמטרים העודפים‪.‬‬
‫בקיצור‪ ,‬בעוד ש‪ parazi-‬ציפתה לקבל ‪ Tuple‬אחד‪ ,‬היא קיבלה ‪ Tuple‬בתוך ‪ – Tuple‬סלט של ‪-Tuple‬ים‪ ,‬וזה רק עם ‪2‬‬
‫פונקציות‪.‬‬

‫עמוד ‪24‬‬
‫‪Python 2.5‬‬

‫ברור שיש פה פתרון‪ ,‬והוא אפילו ממש פשוט‪ :‬בעת הקריאה ל‪ parazi-‬צריך לשים כוכבית לפני ‪ .y‬הכוכבית אומרת ל‪-‬‬
‫‪ Python‬לקחת את ה‪ Tuple-‬הקיים כ‪ Tuple-‬של הפרמטרים העודפים‪ ,‬ולא ליצור ‪ Tuple‬חדש‪ .‬הנה הפונקציות המתוקנות‪:‬‬

‫‪>>> def yanti(x, *y):‬‬


‫‪...‬‬ ‫‪print x ,y‬‬
‫‪...‬‬ ‫)‪parazi(x, *y‬‬
‫‪...‬‬
‫‪>>> def parazi(x, *y):‬‬
‫‪...‬‬ ‫‪print x, y‬‬
‫‪...‬‬

‫והנה מה שיקרה כשנקרא ל‪ yanti-‬המשופצרת‪:‬‬

‫)‪>>> yanti(1, 2, 3‬‬


‫)‪1 (2, 3‬‬
‫)‪1 (2, 3‬‬

‫תיעוד‬
‫תיעוד )או באנגלית ‪ (Documentation‬הוא פעולה שאיננה כתיבת קוד‪ .‬תיעוד הוא כתיבת הערות לתוכניות שלנו כדי‬
‫שאנחנו‪ ,‬או אנשים אחרים‪ ,‬נוכל לקרוא הערות על הקוד ולהבין אותו‪ ,‬במקרה שהוא לא כל‪-‬כך מובן‪.‬‬
‫יש שני סוגים גדולים של תיעוד ב‪:Python-‬‬
‫‪ .1‬סתם תיעוד שזורקים באמצע הקוד‪ ,‬כדי שיהיה יותר ברור‪.‬‬
‫‪ .2‬מחרוזת תיעוד קבועה בתחילת הפונקציה‪.‬‬

‫הסוג הראשון נעשה בצורה פשוטה מאוד – כמו שב‪ C++-‬יש את רצף התווים "‪ "//‬שאומר שמעכשיו ועד סוף השורה יש‬
‫דברים שלא צריך לקמפל )שכנראה יהיו הערות והארות(‪ ,‬כך גם ב‪ Python-‬יש את התו "‪ "#‬שאומר שאין להתייחס למה‬
‫שכתוב מאחרי תו זה ואילך‪:‬‬

‫‪>>> def func():‬‬


‫‪...‬‬ ‫‪print “We have to write something” # ladod moshe hayta para‬‬

‫הסוג השני של תיעוד הוא סוג מיוחד‪ ,‬ואליו ‪ Python‬מתייחסת בצורה שונה – בתחילת פונקציה‪ ,‬שורה אחת אחרי שורת‬
‫ה‪) def-‬בלי שום רווחים מסתוריים(‪ ,‬ניתן לשים מחרוזת )כמובן‪ ,‬עם ‪ TAB‬לפניה(‪ .‬המחרוזת הזאת היא מחרוזת התיעוד של‬
‫הפונקציה‪ .‬כאשר מישהו אחר )או אנחנו( ירצה יום אחד לדעת מהי הפונקציה הזו‪ ,‬הוא יוכל לקבל את המחרוזת בקלות‬
‫רבה‪ .‬העובדה שהתיעוד נמצא בתוך הקוד עצמו הוא דבר מאוד חזק – זה אומר שאם יש לך את הקוד‪ ,‬יש לך את‬
‫התיעוד‪ .‬אין צורך לחפש קובץ תיעוד שנעלם‪ ,‬או יותר גרוע‪ ,‬איזו חוברת שקבורה במגירה של מישהו אחר‪ .‬מושג מחרוזות‬
‫התיעוד בתחילת פונקציות שאול משפת התכנות ‪ ,LISP‬וקרוי ‪) DocStrings‬או ‪(Documentation Strings‬‬

‫‪>>> def tor():‬‬


‫‪...‬‬ ‫”‪“I am a function that does absolutely nothing‬‬
‫‪...‬‬ ‫‪pass‬‬
‫‪...‬‬
‫)(‪>>> tor‬‬
‫__‪>>> tor.__doc‬‬
‫’‪‘I am a function that does absolutely nothing‬‬

‫אז את מחרוזת התיעוד מקבלים ע"י כתיבת שם הפונקציה‪ ,‬נקודה‪ ,‬ו‪ .__doc__ -‬ניתן גם להשתמש בפונקציה המובנית‬
‫)(‪ help‬שיודעת להדפיס בצורה יפה יותר מחרוזת תיעוד של פונקציה )או כל אובייקט אחר עם מחרוזת תיעוד(‪:‬‬

‫)‪>>> help(tor‬‬
‫__‪Help on function tor in module __main:‬‬

‫)(‪tor‬‬
‫‪I am a function that does absolutely nothing‬‬

‫אפשר גם להפעיל את )(‪ help‬על מודול ולראות את רשימת כל הפונקציות שהוא מכיל ואת התיעוד של כל אחת מהן‪.‬‬

‫מחרוזות תיעוד כמו שראינו הן דבר נחמד‪ .‬אבל‪ ,‬ברוב הפעמים נרצה לכלול יותר משורה אחת בתיעוד‪ ,‬שתכיל את מבנה‬
‫הפונקציה‪ ,‬מה היא מחזירה‪ ,‬פרמטרים‪ ,‬תיאור מפורט‪ ,‬וכו'‪ .‬כדי לעשות את זה‪ ,‬כותבים את מחרוזת התיעוד‪ ,‬ומוסיפים‬
‫’‪-‘\n‬ים כאשר רוצים לרדת שורה‪:‬‬

‫‪>>> def func_with_long_doc():‬‬


‫‪...‬‬ ‫”‪“I have a very very very very very\nvery very long documentation‬‬
‫‪...‬‬

‫עמוד ‪25‬‬
‫‪Python 2.5‬‬

‫כדי להדפיס את מחרוזת התיעוד כמו שצריך )ולא את תוכן המחרוזת עצמה(‪ ,‬נשתמש ב‪:print-‬‬

‫__‪>>> print func_with_long_doc.__doc‬‬


‫‪I have a very very very very very‬‬
‫‪very very long documentation‬‬

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

‫‪>>> def f(a, b, c):‬‬


‫‪...‬‬ ‫‪"""f(a, b, c) --> list‬‬
‫‪...‬‬
‫‪...‬‬ ‫‪Takes 3 integers (a, b, c), and returns a list with those‬‬
‫‪...‬‬ ‫‪three numbers, and another number at the end of that list,‬‬
‫‪...‬‬ ‫‪which is the largest number of all three.‬‬
‫‪...‬‬ ‫"""‬
‫‪...‬‬ ‫])‪return [a, b, c, max(a, b, c‬‬
‫‪...‬‬

‫למעשה‪ ,‬כדי ליצור מחרוזת תיעוד בלי להסתבך עם ‪-\n‬ים מגעילים‪ ,‬משתמשים במחרוזת עם ‪ 3‬גרשיים )כפולים או‬
‫בודדים‪ ,‬העיקר שהגרשיים הפותחים והסוגרים יהיו סימטריים(‪ .‬המחרוזת מסתיימת כאשר פיתון פוגשת שוב ‪ 3‬גרשיים‪,‬‬
‫וכל מה שבאמצע‪ ,‬כולל ‪-\n‬ים‪ ,‬נכנס למחרוזת‪:‬‬
‫__‪>>> f.__doc‬‬
‫‪'f(a, b, c) --> list\n\n‬‬ ‫‪Takes 3 integers (a, b, c), and returns a list with‬‬
‫‪those\n‬‬ ‫‪three numbers, and another number at the end of that list,\n‬‬ ‫‪which is‬‬
‫‪the largest number of all three.\n‬‬ ‫'‬

‫כמובן שמומלץ לבחון את המחרוזות עם )(‪ help‬או ‪ print‬ולא להסתכל עליהן ישירות‪.‬‬

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

‫‪def func():‬‬
‫”‪print “Here we go‬‬
‫‪i = 9‬‬
‫‪while i > 0:‬‬
‫‪print i * 5‬‬

‫בפונקציה הזאת‪ ,‬הוכרז משתנה בשם ‪ .i‬המשתנה ‪ i‬יהיה קיים עד שהפונקציה תגיע לסופה‪ ,‬ואז יושמד‪ .‬אם נקרא‬
‫לפונקציות אחרות מתוך הפונקציה ‪ ,func‬הן לא יכירו את המשתנה ‪ .i‬יותר מכך‪ ,‬אם פונקציה אחרת תכריז על משתנה‬
‫באותו השם ‪ ,i‬לכ"א מהפונקציות יהיה משתנה ‪ i‬משלה‪:‬‬

‫‪>>> def alice():‬‬


‫‪...‬‬ ‫‪k = 3‬‬
‫‪...‬‬
‫‪>>> def bob():‬‬
‫‪...‬‬ ‫‪k = 1‬‬
‫‪...‬‬ ‫‪print k‬‬
‫‪...‬‬ ‫)(‪alice‬‬
‫‪...‬‬ ‫‪print k‬‬
‫‪...‬‬
‫)(‪>>> bob‬‬
‫‪1‬‬
‫‪1‬‬

‫בנוסף לכך‪ ,‬יכול להיות מקרה בו פונקציה יוצרת משתנה‪ ,‬אבל המשתנה לא נוצר בתוך הבלוק של הפונקציה‪ ,‬אלא‬
‫באחד מתת‪-‬הבלוקים שלה‪ ,‬בתוך תנאי ‪ if‬או לולאת ‪ for‬או ‪ .while‬במצב כזה‪ ,‬המשתנה שנוצר יהיה תקף וקיים גם אחרי‬
‫היציאה מתת‪-‬הבלוק‪ ,‬בלי שום קשר לזה שהוא נוצר בתוך הבלוק )בשונה מאוד מ‪ Scopes-‬ב‪ C-‬וב‪:(C++-‬‬

‫‪>>> def last_func_for_today():‬‬


‫‪...‬‬ ‫‪e = 3‬‬
‫‪...‬‬ ‫‪while e != 0:‬‬
‫‪...‬‬ ‫‪e -= 1‬‬
‫‪...‬‬ ‫‪if e == 2:‬‬
‫‪...‬‬ ‫‪g = 9.8‬‬

‫עמוד ‪26‬‬
‫‪Python 2.5‬‬

‫‪...‬‬ ‫‪print e, g‬‬


‫‪...‬‬
‫)(‪>>> last_func_for_today‬‬
‫‪0 9.8‬‬

‫החזרת ‪-Tuple‬ים מפונקציה‬


‫ב‪ Python-‬קיים טיפוס הנתונים ‪ .Tuple‬בפרק על טיפוסי הנתונים סקרנו את הטיפוס‪ ,‬וראינו שניתן לאגד מספר ערכים ב‪-‬‬
‫‪ Tuple‬אחד‪ .‬ניתן להשתמש בתכונה זו כדי להחזיר מספר ערכים מפונקציה‪ ,‬ע"י כך שמאגדים אותם ביחד ב‪.Tuple-‬‬
‫לדוגמה‪ ,‬הנה פונקציה שמחזירה שני ערכים‪:‬‬

‫‪>>> def f():‬‬


‫‪...‬‬ ‫)'‪return ('bibibim', 'bobobom‬‬

‫כאשר נשתמש בפונקציה‪ ,‬נוכל לקבל ממנה מיד את שני הערכים לתוך שני משתנים‪:‬‬

‫)(‪>>> str1, str2 = f‬‬


‫‪>>> str1‬‬
‫'‪'bibibim‬‬
‫‪>>> str2‬‬
‫'‪'bobobom‬‬

‫וגם‪ ,‬ברוב המקרים ברור לפיתון שאם ביקשנו מפונקציה להחזיר שני ערכים‪ ,‬היא צריכה לעשות את זה ב‪ .Tuple-‬לכן‪,‬‬
‫במקרים הברורים נוכל להשמיט את הסוגריים‪:‬‬

‫‪>>> def f():‬‬


‫‪...‬‬ ‫'‪return 'bibibim', 'bobobom‬‬

‫והכל יעבוד בדיוק כמו בפונקציה הקודמת‪.‬‬

‫עמוד ‪27‬‬
‫‪Python 2.5‬‬

‫פרק ‪map, reduce, filter, lambda_:7‬‬


‫כמו בכל שפת תכנות‪ ,‬ב‪ Python-‬יש הרבה מקרים בהם יש אוסף של נתונים )רשימה‪ ,‬תור‪ ,‬מחסנית‪ ,‬מערך‪ ,‬וכד'( עליו‬
‫מבצעים עיבוד מסוים‪ .‬העיבוד יכול להיות כמעט כל דבר )קריאה לפונקציות‪ ,‬פעולות בין שני איברים עוקבים‪ ,‬וכד'(‪.‬‬
‫ברוב המקרים‪ ,‬העיבוד הזה ייעשה בלולאה‪.‬‬
‫בשביל המקרים האלה נוצרו הפונקציות ‪ reduce ,map‬ו‪.filter-‬‬

‫שלוש הפונקציות האלה הן פונקציות מובנות ב‪ ,Python-‬שכל מטרתן היא לקחת רשימה )או ‪ ,(Tuple‬להריץ פונקציה על‬
‫האיברים שלה )כ"א משלוש הפונקציות מריצה את הפונקציה בדרך שונה‪ ,‬עם איבר או איברים שונים( ולהפיק פלט‬
‫מתאים‪.‬‬
‫כל זה נעשה ע"י קריאה לפונקציה אחת על הרשימה‪ ,‬דבר שחוסך כתיבה מחדש של לולאה טריוויאלית בכל פעם‬
‫מחדש )ולפעמים קצת יותר מלולאה טריוויאלית(‪.‬‬

‫‪map‬‬
‫פונקצית קסם ראשונה‪.‬‬
‫‪ map‬מקבלת רשימה ופונקציה‪ .‬הפונקציה חייבת לקבל פרמטר אחד בלבד‪ map .‬מריצה את הפונקציה עם כ"א מאיברי‬
‫הרשימה )כל איבר בתורו‪ ,‬לפי הסדר בו הם מופיעים ברשימה(‪.‬‬
‫‪ map‬מחזירה רשימה חדשה‪ ,‬ובה כל איבר הוא התוצאה של הפונקציה עם האיבר המתאים לו ברשימה המקורית‪.‬‬
‫בעברית‪ map :‬לוקחת את האיבר הראשון‪ ,‬מריצה עליו את הפונקציה‪ ,‬ושמה את התוצאה ברשימה החדשה‪ .‬אח"כ היא‬
‫לוקחת את האיבר השני‪ ,‬מריצה עליו את הפונקציה‪ ,‬ושמה את התוצאה באיבר הבא ברשימה החדשה‪ .‬כך היא עושה‬
‫לכל האיברים‪.‬‬

‫‪>>> def func(x):‬‬


‫‪...‬‬ ‫‪return x * 2‬‬
‫‪...‬‬
‫))‪>>> map(func, range(1, 11‬‬
‫]‪[2, 4, 6, 8, 10, 12, 14, 16, 18, 20‬‬

‫‪reduce‬‬
‫פונקצית קסם שניה‪.‬‬
‫‪ reduce‬מקבלת רשימה ופונקציה‪ .‬הפונקציה חייבת לקבל שני פרמטרים‪ reduce .‬לוקחת את שני האיברים הראשונים‬
‫ברשימה ומריצה את הפונקציה כאשר האיבר הראשון הוא הפרמטר הראשון והאיבר השני הוא הפרמטר השני של‬
‫הפונקציה‪ .‬לאחר מכן‪ reduce ,‬לוקחת את התוצאה של הפונקציה ומריצה את הפונקציה עם התוצאה כפרמטר הראשון‬
‫והאיבר הבא מהרשימה כפרמטר השני‪ .‬כך היא ממשיכה עד סוף הרשימה‪.‬‬
‫אם ברשימה יש רק איבר אחד‪ reduce ,‬תחזיר את האיבר היחיד ברשימה )מבלי להריץ את הפונקציה(‪ .‬אם הרשימה‬
‫ריקה‪ reduce ,‬תקרוס ותדפיס הודעת שגיאה‪.‬‬

‫‪>>> def func(x, y):‬‬


‫‪...‬‬ ‫‪return x + y‬‬
‫‪...‬‬
‫))‪>>> reduce(func, range(1, 11‬‬
‫‪55‬‬

‫בדוגמה הזו הודפס הסכום של כל המספרים בין ‪ 1‬ל‪.10-‬‬

‫‪filter‬‬
‫פונקצית קסם שלישית‪.‬‬
‫‪ filter‬מקבלת רשימה ופונקציה‪ .‬הפונקציה חייבת לקבל פרמטר אחד‪ filter .‬תיקח כ"א מאיברי הרשימה ותריץ את‬
‫הפונקציה עם האיבר הזה‪ .‬אם התוצאה של ריצת הפונקציה היא ‪) True‬איננה אפס‪ ,‬איננה מחרוזת ריקה‪ ,‬ולא הופכת‬
‫לאפס אם עושים לה ‪ Casting‬ל‪ ,(Integer-‬האיבר )האיבר מהרשימה שהועברה ל‪ ,filter-‬לא ערך ההחזרה של הפונקציה(‬
‫יתווסף לרשימת התוצאה‪.‬‬
‫‪ filter‬למעשה מאפשרת לנו לסנן ערכים מרשימה נתונה‪ ,‬בשורה אחת בלבד‪.‬‬

‫‪>>> def func(x):‬‬


‫‪...‬‬ ‫‪return x % 2‬‬
‫‪...‬‬
‫>>>‬
‫))‪>>> filter(func, xrange(20‬‬
‫]‪[1, 3, 5, 7, 9, 11, 13, 15, 17, 19‬‬

‫בדוגמה הזו הודפסו כל המספרים בין ‪ 0‬ל‪ 19-‬ששארית החלוקה שלהם ב‪ 2-‬איננה אפס‪ .‬בקיצור‪ ,‬כל המספרים האי‪-‬‬
‫זוגיים‪.‬‬
‫ניתן כמובן להפוך את התנאי ולהדפיס את כל המספרים הזוגיים‪:‬‬

‫עמוד ‪28‬‬
‫‪Python 2.5‬‬

‫‪>>> def func(x):‬‬


‫‪...‬‬ ‫‪return not x % 2‬‬
‫‪...‬‬
‫))‪>>> filter(func, xrange(20‬‬
‫]‪[0, 2, 4, 6, 8, 10, 12, 14, 16, 18‬‬

‫‪lambda‬‬
‫אז מה ‪ lambda‬עושה בכלל ולמה היא קשורה לפרק הזה?‬
‫כמו שאפשר לראות בדוגמאות למעלה‪ ,‬עבור כ"א מההרצות של ‪ reduce ,map‬או ‪ filter‬היינו צריכים לכתוב פונקציה‬
‫חדשה כדי שנוכל להעביר פונקציה לכ"א מהפונקציות‪ .‬אבל כתיבת פונקציה חדשה כל פעם זה סתם העמסה על‬
‫הקוד‪ ,‬ולפעמים גם יכול להיות מסובך למצוא את הפונקציה )אם שמנו אותה במקום אחר(‪.‬‬
‫‪ lambda‬מאפשרת לנו לחסוך עוד יותר בכמות הקוד – במקום לכתוב פונקציה חדשה בכל פעם‪ lambda ,‬יוצרת עבורנו‬
‫פונקציה ללא‪-‬שם‪ ,‬כבר בתוך שורת הקוד של ‪ reduce ,map‬או ‪.filter‬‬
‫בת'כלס‪ ,‬כאשר יוצרים פונקציה‪ ,‬השם שנותנים לפונקציה הוא מצביע לפונקציה עצמה‪ .‬זאת גם הסיבה שכאשר כותבים‬
‫שם של פונקציה‪ ,‬בלי סוגריים‪ Python ,‬כותבת לנו את שם הפונקציה‪ .‬באופן הזה‪ lambda ,‬יוצרת עבורנו פונקציה חדשה‪,‬‬
‫ומחזירה את המצביע לפונקציה החדשה‪ .‬לפונקציה החדשה אין שם‪ ,‬וכאשר תסתיים הרצת ‪ reduce ,map‬או ‪ ,filter‬גם‬
‫הפונקציה חסרת‪-‬השם תימחק‪.‬‬
‫דוגמה קטנה כדי להבין יותר טוב מה קורה‪:‬‬

‫יצרנו פונקציה חדשה‬

‫‪>>> def func():‬‬ ‫הנה הכתובת שלה‬


‫‪...‬‬ ‫‪return 5‬‬
‫‪...‬‬
‫‪>>> func‬‬
‫>‪<function func at 0x00AD57A0‬‬ ‫וזו הכתובת של פונקצית ‪lambda‬‬
‫‪>>> lambda x:x + 2‬‬ ‫חדשה שזה הרגע נוצרה‪.‬‬
‫>‪<function <lambda> at 0x00AFB3D0‬‬

‫קצת על המבנה של ‪ :lambda‬כתיבת פונקצית ‪ lambda‬למעשה כולל רק את הפרמטרים לפונקציה ואת ערך ההחזרה‬
‫שלה‪ ,‬כי למעשה אין צורך ביותר מכך )פונקציות ‪ lambda‬הן ל"שימוש חד‪-‬פעמי"(‪.‬‬
‫והנה דוגמה לשימוש ב‪ map-‬ו‪ lambda-‬ביחד‪ .‬הדוגמה עושה את מה שעושה הדוגמה הראשונה – מקבלת רשימת‬
‫מספרים ומחזירה רשימה של האיברים המקוריים כפול ‪:2‬‬

‫))‪>>> map(lambda x:x*2, range(1, 11‬‬


‫]‪[2, 4, 6, 8, 10, 12, 14, 16, 18, 20‬‬

‫בדוגמה הזו נכתבה פונקצית ‪ lambda‬המקבלת פרמטר אחד – ‪ – x‬ומחזירה את ‪ .x*2‬כמובן‪ ,‬אפשר לכתוב כל ביטוי‬
‫שתלוי ב‪ ,x-‬ואפשר גם לכלול פונקציות בביטוי הזה‪.‬‬

‫למעשה‪ ,‬כאשר אנו כותבים את פונקציית ה‪ lambda-‬הבאה‪:‬‬

‫‪>>> f = lambda x: x * 2‬‬

‫יצרנו פונקציה‪ ,‬אותה יכולנו ליצור באופן הבא‪:‬‬

‫‪>>> def f(x):‬‬


‫‪...‬‬ ‫‪return x * 2‬‬
‫‪...‬‬

‫התוצאה היא זהה לחלוטין בשני המקרים‪.‬‬

‫שימוש ב‪ reduce ,map-‬ו‪ filter-‬ביחד‬


‫שלוש הפונקציות לבדן אינן הסוף – אפשר לשלב כמה פונקציות כאלה ביחד‪ :‬למשל‪ ,‬התוצאה של ‪ map‬תהיה הרשימה‬
‫של ‪ ,filter‬וכד'‪.‬‬
‫הנה שתי דוגמאות לשימושים כאלה‪:‬‬

‫פונקציה שמחזירה האם מספר הוא ראשוני‪:‬‬

‫‪def is_primary(n):‬‬
‫)))‪return reduce(lambda x, y: x and y, map(lambda x: n % x, range(2, n‬‬

‫פונקציה שמחזירה את סכום הספרות במספר‪:‬‬

‫‪def sum_of_digits(n):‬‬
‫))))‪return reduce(lambda x,y:x+y, map(int, map(None, str(n‬‬
‫עמוד ‪29‬‬
‫‪Python 2.5‬‬

‫מילה על יעילות‬
‫ישנה כמובן השאלה – מה יעיל יותר‪ ,‬להשתמש בלולאה רגילה )‪ ,(for ,while‬או להשתמש )כשאפשר( ב‪reduce ,map-‬‬
‫או ‪?filter‬‬
‫כנראה )עקב מימוש( יעיל יותר להשתמש ב‪ reduce ,map-‬ו‪ filter-‬במקום בלולאה רגילה בגלל שהפונקציות עצמן‬
‫ממומשות ב‪ ,C-‬או בכל שפה עילית אחרת‪ .‬היות והמימוש הוא בשפה נמוכה יותר מ‪ ,Python-‬הריצה שלה תהיה מהירה‬
‫יותר‪.‬‬
‫מהכיוון ההפוך – כאשר מריצים לולאה רגילה ב‪ ,Python-‬יש צורך באחזקת משתנה )‪ i‬לצורך הענין(‪ ,‬או רשימה )‪range‬‬
‫לסוגיה(‪ .‬האחזקה הזו לוקחת גם זיכרון וגם עיבוד נוסף )שנסתר ונחסך מהמתכנת(‪ ,‬ולכן היא "יקרה" יותר‪.‬‬
‫השאלה הזו לא מוצגת כדי שנחשוב טוב טוב לפני שכותבים משהו ב‪ Python-‬או ב‪ ,C-‬אלא כדי להדגיש ששימוש‬
‫בפונקציות פנימיות הוא לרוב מהיר יותר‪ .‬כמו כן‪ ,‬לא צריך להשתגע ולכתוב תוכניות שלמות עם קריאות מסובכות ל‪-‬‬
‫‪ reduce ,map‬ו‪.filter-‬‬
‫טוב להשתמש ב"קיצורי דרך"‪ ,‬כל עוד הם גם משפרים את התוכנית‪ ,‬הופכים אותה לקריאה יותר וקלה יותר ל‪.Debug-‬‬

‫עמוד ‪30‬‬
‫‪Python 2.5‬‬

‫פרק ‪_:8‬מודולים‬
‫מהו מודול?‬
‫מודול הוא בסה"כ קובץ שמכיל קוד ‪ .Python‬לרוב‪ ,‬לקובץ של מודול ‪ Python‬תהיה סיומת ‪ ,py‬אך קיימות גם סיומות‬
‫אחרות‪ ,‬לדוגמה ‪ dll‬או ‪) so‬ב‪ Windows-‬או ‪ ,(UNIX‬שמציינות קובץ שמכיל פונקציות ‪ Python‬שכתובות ב‪) C-‬או באיזושהי‬
‫שפה מקומפלת אחרת(‪ .‬לדוגמה‪ ,‬המודול ‪) os‬אותו נכיר עוד מעט( כתוב ב‪.C-‬‬
‫כאשר קובץ הוא בעל סיומת ‪ Python ,py‬יודעת שהקובץ מכיל טקסט רגיל‪ ,‬ושיש להתייחס אליו כאל קוד ‪ .Python‬קוד‬
‫‪ Python‬הוא כל דבר שהכרנו עד עכשיו – משתנים‪ ,‬פונקציות‪ ,‬שימושים במודולים אחרים‪ ,if ,‬ולולאות‪ .‬אם ניצור פונקציה‬
‫בקובץ כלשהו‪ ,‬ונשמור אותו עם סיומת ‪ ,py‬נוכל לטעון אותו ל‪ Interpreter-‬או למודול אחר ולהשתמש בפונקציה‬
‫שכתבנו‪.‬‬

‫לדוגמה‪ ,‬נניח שיש לנו את הקובץ הבא‪ ,‬שנקרא ‪:example.py‬‬

‫‪def func1(x):‬‬
‫))‪return map(lambda i: i * 2, xrange(0, x‬‬

‫‪def func2(x):‬‬
‫‪return 2 ** x‬‬

‫‪def func3(x):‬‬
‫‪return “The number is %d” % x‬‬

‫‪def func4(x):‬‬
‫‪return [x] * x‬‬

‫בקובץ זה ‪ 4‬פונקציות‪ ,‬כאשר שם הקובץ בו הן מאוחסנות הוא ‪ .example.py‬ייבוא הקובץ לתוך התוכנית שלנו )או לצורך‬
‫הדוגמה‪ ,‬ל‪ (Interpreter-‬ייעשה באמצעות הפקודה ‪.import‬‬
‫לפקודה ‪ import‬שתי צורות עיקריות‪ ,‬כאשר כל‪-‬אחת מהן תשפיע בדרך מסוימת על האופן בו הפונקציות ייובאו למודול‪.‬‬
‫צורה ראשונה מאפשרת ייבוא כל הפונקציות מהמודול לתוך ה‪ namespace-‬הגלובלי‪ .‬המשמעות היא שכאשר נרצה‬
‫להשתמש בפונקציה מהמודול‪ ,‬פשוט נכתוב את השם שלה‪.‬‬
‫צורה שניה היא ייבוא המודול ל‪ namespace-‬משלו‪ ,‬וכאשר נרצה להשתמש בפונקציה מהמודול‪ ,‬נצטרך לרשום את שם‬
‫המודול ושם הפונקציה‪ .‬צורה זו בטוחה יותר ודואגת שלא יהיו התנגשויות בין שמות פונקציות ממודולים שונים‪.‬‬
‫כאשר יש משתנים גלובליים מיוצאים ממודול‪ ,‬תמיד יש לכתוב גם את שם המודול וגם את שם המשתנה בפנייה אליו‪,‬‬
‫בלי קשר לצורת ייבוא המודול‪.‬‬
‫לדוגמה‪ ,‬הנה קוד שמייבא את ‪ examply.py‬ע"י הכנסתו ל‪ namespace-‬משלו‪:‬‬

‫‪>>> import example‬‬


‫)‪>>> example.func1(2‬‬
‫]‪[0, 2‬‬
‫)‪>>> example.func3(65‬‬
‫'‪'The number is 65‬‬
‫)‪>>> example.func4(17‬‬
‫]‪[17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17‬‬

‫כפי שניתן לראות‪ ,‬אין לכתוב את שם הקובץ כולו‪ ,‬אלא להשמיט את הסיומת ‪ .py‬כמו כן‪ ,‬הפונקציות מיובאות לתוך‬
‫‪ namespace‬ששמו הוא כשם המודול‪ .‬אותו ‪ namespace‬הוא בעצם אובייקט מסוג "מודול"‪ ,‬כלומר אובייקט המדמה את‬
‫המודול כאשר אבריו הם השמות והאובייקטים המיוצאים ממנו‪.‬‬
‫הקוד הבא מייבא את ‪ example.py‬ל‪ namespace-‬הגלובלי‪:‬‬

‫* ‪>>> from example import‬‬


‫)‪>>> func1(2‬‬
‫]‪[0, 2‬‬
‫)‪>>> func2(5‬‬
‫‪32L‬‬
‫)‪>>> func3(7‬‬
‫'‪'The number is 7‬‬

‫מבנה פקודת ה‪ import-‬במקרה הזה הוא יותר מורכב‪ .‬בדוגמה הזו בוצע ייבוא לכל הפונקציות במודול ‪ ,example‬ולכן‬
‫הסימן *‪ .‬ניתן לבצע ייבוא שכולל רק חלק מהפונקציות במודול‪ .‬כמו כן‪ ,‬הפונקציות יובאו כך שניתן לקרוא להן כאילו‬
‫הן הוגדרו הרגע ב‪) Interpreter-‬או בקוד בו עובדים(‪.‬‬
‫כאשר כותבים תוכניות גדולות‪ ,‬קבצי ‪ Script‬וכד'‪ ,‬מקובל לשים את פקודות ה‪ import-‬בתחילת הקובץ‪ ,‬בדומה ל‪include-‬‬
‫ב‪.C-‬‬

‫דוגמה נוספת ל‪ import-‬היא ייבוא של מספר פונקציות ספציפיות ממודול‪ ,‬ולא את כל הפונקציות מהמודול‪:‬‬

‫עמוד ‪31‬‬
‫‪Python 2.5‬‬

‫‪>>> from example import func1, func2‬‬


‫)‪>>> func1(6‬‬
‫]‪[0, 2, 4, 6, 8, 10‬‬
‫)‪>>> func2(4‬‬
‫‪16L‬‬
‫)‪>>> func3(7‬‬
‫‪Traceback (most recent call last):‬‬
‫>‪File "<stdin>", line 1, in <module‬‬
‫‪NameError: name 'func3' is not defined‬‬

‫ניתן לראות כי ‪ func1‬ו‪ func2-‬יובאו מ‪ ,example-‬אבל ‪ func3‬לא מוכרת כלל משום שצויין לייבא רק את ‪ func1‬ו‪.func2-‬‬

‫כדי לדעת אילו פונקציות קיימות במודול‪ ,‬נוכל להשתמש בפונקציה המובנית )(‪:dir‬‬
‫)‪>>> dir(example‬‬
‫‪['__builtins__', '__doc__', '__file__', '__name__', 'func1', 'func2', 'func3',‬‬
‫]'‪'func4‬‬

‫אפשר לראות שבעזרת )(‪ dir‬אנחנו רואים את כל הפונקציות שיצרנו – ‪ .func1, func2, func3, func4‬למעשה )(‪ dir‬מחזירה‬
‫רשימה של מחרוזות‪ ,‬כאשר כל מחרוזת היא שם של אובייקט כלשהו בתוך המודול‪.‬‬
‫אנחנו יכולים לראות מהדוגמה שלמודולים יש עוד כמה ‪ Attributes‬נחמדים כמו __‪ __name‬או __‪:__file‬‬

‫__‪>>> example.__name‬‬
‫'‪'example‬‬
‫__‪>>> example.__file‬‬
‫’‪‘example.py‬‬

‫כמובן שאם אנחנו משתמשים במודול ‪ example‬אנחנו כבר יודעים שקוראים לו ‪ ,example‬אבל __‪ __name‬שימושי דווקא‬
‫מתוך המודול‪ ,‬למשל אם נרצה לכתוב קוד שלא תלוי בשם של המודול‪ ,‬נוכל להשתמש ב‪ __name__-‬כפרמטר‪.‬‬

‫__‪ __doc‬הוא ה‪ Documentation String-‬של המודול‪ ,‬בדומה למחרוזת תיעוד של פונקציות‪ .‬כדי ליצור מחרוזת תיעוד‬
‫למודול‪ ,‬פשוט נשים מחרוזת בתחילת המודול‪ ,‬לפני פונקציות או ‪import‬ים אחרים‪:‬‬

‫‪"""This is an example module‬‬


‫‪with 4 functions.‬‬
‫"""‬

‫‪import os‬‬

‫‪def func1(x):‬‬
‫))‪return map(lambda i: i * 2, xrange(0, x‬‬

‫‪def func2(x):‬‬
‫‪return 2 ** x‬‬

‫‪def func3(x):‬‬
‫‪return "The number is %d" % x‬‬

‫‪def func4(x):‬‬
‫‪return [x] * x‬‬

‫את המחרוזת הזו נוכל אח"כ לראות ע"י גישה ל‪ __doc__-‬או בעזרת )(‪.help‬‬

‫הרצת קבצי ‪ Python‬ב‪Windows-‬‬


‫עכשיו כשאנחנו יודעים איך לחלק את הקוד שלנו לכמה קבצים‪ ,‬הדבר הבא שכנראה נרצה לעשות הוא להריץ קובץ‬
‫פיתון בתור תוכנית‪ .‬ממש כמו שאנחנו כותבים תוכנית ‪ ,C‬מקמפלים ומריצים אותה‪ ,‬נרצה לכתוב תוכנית פיתון ולהריץ‬
‫אותה‪ .‬אין צורך לקמפל‪ ,‬כי ניתן פשוט להריץ את הקוד כמו שהוא‪.‬‬
‫לדוגמה‪ ,‬ניצור את הקובץ הבא ונקרא לו ‪:quick_script.py‬‬

‫”?‪print “What’s your cat name‬‬


‫)“(‪cat_name = raw_input‬‬

‫”?‪print “What’s your dog name‬‬


‫)“(‪dog_name = raw_input‬‬

‫)‪print “You have a dog named %s and a cat named %s” % (dog_name, cat_name‬‬

‫עמוד ‪32‬‬
‫‪Python 2.5‬‬

‫לפני שנמשיך נציין שמקובל לקרוא לקבצי פיתון שנועדו להרצה ‪) Script‬או תסריט‪ ,‬סקריפט(‪ .‬אין כמובן הבדל בין קובץ‬
‫פיתון לקובץ פיתון אחר מבחינת פיתון‪ .‬ההבדל היחיד הוא בצורת השימוש‪.‬‬

‫עכשיו‪ ,‬בהנחה ש‪ Python-‬מותקנת על המחשב‪ ,‬נוכל להריץ את התוכנית שכתבנו‪ .‬לדוגמה‪ ,‬נעשה זאת מ‪:cmd-‬‬

‫‪C:\> C:\Python25\Python.exe quick_script.py‬‬


‫?‪What's your cat name‬‬
‫‪Bush‬‬
‫?‪What's your dog name‬‬
‫‪Charly‬‬
‫‪You have a dog named Charly and a cat named Bush‬‬

‫כלומר כדי להריץ את ‪ quick_script.py‬משורת הפקודה‪ ,‬אנחנו צריכים לציין שאנחנו רוצים להריץ את ‪Python.exe‬‬
‫מהספרייה בה הוא מותקן )המיקום הדיפולטי הוא ‪ ,C:\Python25‬עבור גרסה ‪ 2.5‬כמובן( ולאחר מכן לתת את שם‬
‫הסקריפט‪.‬‬
‫כאשר מתקינים את פיתון על ‪ Windows‬אפשר גם להריץ את הסקריפט ע"י ‪ .Double-Click‬החסרון היחיד הוא שאם יש‬
‫שגיאה בהרצת הסקריפט‪ ,‬לא נוכל לראות אותה כי החלון של פיתון ייסגר‪.‬‬

‫הרצת קבצי ‪ Python‬ב‪UNIX-‬‬


‫הרצת סקריפטי פיתון ב‪ UNIX-‬דומה לרצה שלהם ב‪ ,Windows-‬למעט כמה הבדלים‪.‬‬
‫אם אין לך ‪ ,Unix‬ואינך רוצה ללמוד איך להפעיל תוכנית ‪ Python‬על ‪ ,Unix‬אפשר לדלג על סעיף זה‪ .‬בכל מקרה‪ ,‬כדאי‬
‫להתנסות קצת ב‪ Python-‬על ‪ ,Unix‬גם אם אתה לא ממש מבין חלק מהמושגים בסעיף זה‪.‬‬
‫במערכות ‪ Unix‬למיניהן )מומלץ לעבוד עם ‪ ,Linux‬כי ‪ Python‬כבר באה עם רוב ההפצות של ‪ ,(Linux‬יש צורך בכיוון של‬
‫התוכנית שמריצה את קובץ ה‪ .py-‬כיוונון זה נעשה כמו ב‪ ,Perl-‬ע"י כתיבת תוכנית הפעלה כשורת ‪ Comment‬בשורה‬
‫הראשונה‪ .‬כמו כן‪ ,‬יש לסמן את הקובץ כקובץ ‪ executable‬עם ‪.chmod‬‬
‫הנה הקובץ מהדוגמה הקודמת עם התוספת של השורה הראשונה )כאשר ההנחה היא שהתוכנה המריצה נמצאת ב‪-‬‬
‫‪ ,/usr/bin/python‬ושם היא נמצאת ברוב ה‪ Distributions-‬של ‪:(Linux‬‬

‫‪#!/usr/bin/python‬‬

‫”?‪print “What’s your cat name‬‬


‫)“(‪cat_name = raw_input‬‬

‫”?‪print “What’s your dog name‬‬


‫)“(‪dog_name = raw_input‬‬

‫)‪print “You have a dog named %s and a cat named %s” % (dog_name, cat_name‬‬

‫והנה הוא רץ‪:‬‬

‫‪~$ ./quick_script.py‬‬
‫?‪what’s your cat name‬‬
‫‪bush‬‬
‫?‪what’s your dog name‬‬
‫‪charly‬‬
‫!‪you have a dog named charly and a cat named bush‬‬

‫באופן כללי‪ ,‬מאוד נוח לכתוב ‪-Script‬ים שרצים ב‪ Unix-‬כמו תוכניות רגילות‪.‬‬

‫פרמטרים לתוכנית פיתון‬


‫דבר נחמד שאנחנו יכולים לעשות בפיתון הוא להעביר לסקריפט פרמטרים בשורת הפקודה‪ ,‬בדומה לתוכנית בהרבה‬
‫שפות אחרות‪ .‬כל פרמטר שנעביר ייכנס ל‪ ,sys.argv-‬ונוכל לגשת ל‪ sys.argv-‬כדי לראות את הפרמטרים האלה‪ .‬לדוגמה‪,‬‬
‫נכתוב תוכנית קצרה שמדפיסה את הפרמטרים שהיא מקבלת‪:‬‬
‫‪XXX‬‬

‫‪#!/usr/bin/python‬‬
‫‪import sys‬‬
‫‪print sys.argv‬‬

‫ונריץ‪:‬‬

‫‪~$ ./example.py python is cool‬‬


‫]'‪['example.py', 'python', 'is', 'cool‬‬

‫וכמו שאפשר לראות‪ ,‬הפרמטרים לתוכנית‪ ,‬כולל שם התוכנית עצמה‪ ,‬נכנסים לרשימה ב‪.sys.argv-‬‬

‫עמוד ‪33‬‬
‫‪Python 2.5‬‬

‫פרק ‪_:9‬מודולים נפוצים‬


‫הגרסאות העדכניות של ‪ Python‬מסופקות עם המון )ממש המון( מודולים לשימוש של המתכנתים בה‪ .‬ידע והכרה של‬
‫המודולים חשובים לא פחות מהיכרות עם השפה‪ ,‬בגלל שכמו ש‪ Python-‬חוסכת זמן בתכנות ומאפשרת כתיבה של‬
‫תוכניות חכמות וקצרות בהרבה‪ ,‬כך גם הספריות שמסופקות איתה – הן כוללות הרבה מחלקות )את נושא המחלקות‬
‫נלמד בהמשך( ופונקציות לשימושים חוזרים‪ ,‬וחוסכות זמן בבניה של כלים שכבר קיימים ומוכנים לשימוש‪.‬‬
‫פרק זה מכסה כמה מודולים אותם טבעי ללמוד בתחילת העבודה עם מודולים חיצוניים‪ ,‬כי הם כוללים הרבה פונקציות‬
‫שכבר קיימות בשפות אחרות‪ ,‬ויותר נוח לראות כיצד מתבצעת ההקבלה ל‪ .Python-‬אבל‪ ,‬בגרסאות העדכניות של‬
‫‪ Python‬יש עשרות מודולים שונים ומשונים‪ ,‬ובהם ניתן למצוא הרבה מימושים של דברים שקיימים בשפות אחרות )כמו‬
‫‪ Regular Expressions‬מ‪ Perl-‬או מודול ל‪ ,(Random-‬או פונקציות לקישור למערכת ההפעלה )כמו מודול ה‪Socket-‬‬
‫שמאפשר ליצור ‪-socket‬ים לתקשורת באינטרנט(‪ ,‬והרבה מעבר לכך‪.‬‬
‫שוב‪ ,‬הפרק לא מכסה את כל המודולים‪ ,‬אלא כמה מודולים בסיסיים שחשוב להכיר‪ ,‬ושוב‪ ,‬במטרה לתת מבוא‬
‫והסברים לדברים שעלולים להיות לא מובנים‪ ,‬ולא כדי לתרגם את התיעוד לעברית‪.‬‬
‫מומלץ לרפרף על התיעוד של הספריות הקיימות )למשל בתיעוד של ‪ ActivePython‬ל‪ (Windows-‬כדי לראות מה כבר‬
‫קיים‪.‬‬

‫המודול ‪os‬‬
‫מודול זה מכיל פונקציות לתקשורת עם מערכת ההפעלה‪ .‬המודול לא תלוי במערכת ההפעלה עליה מורצת תוכנית ה‪-‬‬
‫‪ .Python‬קיימות הספריות ‪ nt‬ו‪ posix-‬לתקשורת עם מערכות הפעלה ‪ Windows-NT‬ו‪-UNIX-‬ים למיניהם‪ ,‬אבל ‪ os‬מכילה‬
‫פונקציות ומשתנים שיעבדו על כל מערכת‪.‬‬
‫כדי להשתמש במודול נכתוב‪:‬‬

‫‪>>> import os‬‬

‫בתוך המודול קיים משתנה ‪ name‬המכיל את שם מערכת‪-‬ההפעלה עליה מורצת ‪:Python‬‬

‫‪>>> os.name‬‬
‫’‪‘nt‬‬

‫המשתנה יכיל את סוג מערכת ההפעלה‪ ,‬ולא שם מלא כמו "‪ "Windows 95‬וכד'‪ .‬כאשר ‪ Python‬מורצת על מערכת ‪,Java‬‬
‫‪ os.name‬יכיל את המחרוזת ’‪.‘java‬‬

‫המשתנה ‪ environ‬במודול הוא מילון המכיל את משתני הסביבה של המערכת )כמו המיקום של ספריית ה‪.(temp-‬‬
‫משתני הסביבה משתנים ממערכת למערכת‪ ,‬אך ניתן לראות את כל המשתנים הללו ע"י קריאה ל‪ keys()-‬של המילון‪:‬‬

‫)(‪>>> os.environ.keys‬‬
‫‪[‘WINBOOTDIR', 'PATH', 'BLASTER', 'PATHEXT', 'TEMP', 'COMSPEC', 'PROMPT', 'WINDIR',‬‬
‫]’‪'TMP‬‬

‫הפונקציה )(‪ system‬במודול מאפשרת להריץ פקודות של ה‪ Command Line-‬ולקבל את הפלט שלהן בערך ההחזרה של‬
‫הפונקציה‪ .‬שימוש נחמד יכול להריץ את הפקודה ‪:dir‬‬

‫‪>>> import os‬‬


‫)'‪>>> os.system('dir z:\\x‬‬
‫‪Volume in drive Z is Shared‬‬
‫‪Volume Serial Number is 0C17-3468‬‬

‫‪Directory of z:\x‬‬

‫‪07/31/2002‬‬ ‫‪10:08p‬‬ ‫>‪<DIR‬‬ ‫‪.‬‬


‫‪07/31/2002‬‬ ‫‪10:08p‬‬ ‫>‪<DIR‬‬ ‫‪..‬‬
‫)‪0 File(s‬‬ ‫‪0 bytes‬‬
‫‪2 Dir(s) 10,223,505,408 bytes free‬‬
‫‪0‬‬
‫>>>‬

‫הפונקציה למעשה מחזירה ערך‪ ,‬בדוגמה זהו ‪ ,0‬ובנוסף לכך מודפס למשך כל מה שהפקודה שלחה להדפסה למסך‪.‬‬
‫זאת הסיבה שהשורה האחרונה היא ‪ – 0‬זו לא השורה האחרונה‪ ,‬אלא ערך ההחזרה של הרצת הפקודה‪.‬‬

‫הפונקציה )(‪ mkdir‬ו‪ rmdir()-‬יוצרות ומוחקות ספריות‪ ,‬אבל ההבדל בין שימוש ב‪ sysetm()-‬כדי לשגר פקודת מערכת לבין‬
‫השימוש בכ"א מהפונקציות הללו הוא שהפונקציות מתאימות לכל מערכת‪-‬הפעלה‪ ,‬והשימוש ב‪ system()-‬מצריך יצירת‬
‫פקודה שונה לכל מערכת‪.‬‬

‫מודול ‪ os‬מכיל עוד פונקציות‪ ,‬בעיקר לטיפול בקבצים ותהליכים‪.‬‬

‫עמוד ‪34‬‬
‫‪Python 2.5‬‬

‫המודול ‪sys‬‬
‫המודול ‪ sys‬מכיל את כל הפונקציות שקשורות למערכת ה‪ Python-‬ולהרצת תוכנית ה‪ .Python-‬המודול כולל בתוכו‬
‫פונקציות לטיפול בקלט ופלט )לסוגיו השונים(‪ ,‬מידע על גירסת ה‪ ,Interpreter-‬משתנים שמשפיעים על התצוגה‪ ,‬מידע‬
‫על המודולים הטעונים‪ ,‬סדר הבתים )אינדיאניות(‪ ,‬גודל ה‪ ,int-‬ועוד‪.‬‬

‫כמה משתנים חשובים שיש במודול הם ‪ – version‬מכיל את גירסת ה‪ Interpreter-‬עליה מורצת התוכנית‪– platform ,‬‬
‫מכיל את סוג מערכת ההפעלה עליה רצה התוכנית )בניגוד ל‪ ,os.name-‬מכיל רק את סוג מערכת ההפעלה‪ ,‬למשל‬
‫’‪ – path ,(‘win32‬מכיל את כל הספריות בהן ייעשה חיפוש בעת טעינת מודולים‪ ,‬ו‪ – maxint-‬מכיל את גבול משתנה ה‪.int-‬‬

‫כמו כן‪ ,‬המודול מכיל שלושה משתנים – ‪ stdout ,stdin‬ו‪ .stderr-‬אלו הם אובייקטי הקבצים של הקלט הסטנדרטי )לרוב‬
‫המקלדת(‪ ,‬הפלט הסטנדרטי )לרוב המסך( ופלט השגיאות הסטנדרטי )המסך או קובץ(‪ .‬ניתן לכתוב ולקרוא מקבצים‬
‫אלה )כל קובץ וההרשאות שלו – ברור לדוגמה שאי‪-‬אפשר לקרוא מ‪ (stdout-‬לשימושים מיוחדים‪ .‬הפונקציות ‪ print‬ו‪-‬‬
‫‪ raw_input‬משתמשות באובייקטים אלה‪.‬‬

‫כאשר מריצים ‪-script‬ים מה‪ Command Line-‬ניתן לתת להם ארגומנטים‪ ,‬ממש כמו לכל תוכנית רגילה‪ .‬ב‪ C-‬לפונקציה‬
‫)(‪ main‬היו שני פרמטרים – ‪ argc‬ו‪ ,argv-‬בהם הועברו ארגומנטים אלה‪ .‬ב‪ Python-‬קיימת רשימה בשם ‪ argv‬בתוך ‪.sys‬‬
‫הרשימה מכילה את הארגומנטים‪ ,‬לפי הסדר בו הם הועברו‪ ,‬כאשר הארגומנט הראשון הוא לרוב שם הקובץ המורץ‪ .‬אם‬
‫ה‪ script-‬שרץ כרגע )או לצורך העניין ה‪ (Interpreter-‬לא הורץ משורת הפקודה‪ argv ,‬היא רשימה ריקה‪.‬‬

‫המודול ‪string‬‬
‫מודול זה מכיל‪ ,‬בנוסף לפונקציות שיכולות לפעול על מחרוזות שכבר הכרנו בפרק על טיפוסי נתונים‪ ,‬גם כמה מחרוזות‬
‫קבועות שמכילות אוספים של תווים שימושיים – ‪ uppercase‬מכילה את כל האותיות הגדולות‪ lowercase .‬מכילה את כל‬
‫האותיות הקטנות‪ digits .‬מכילה את כל הספרות )‪ 0‬עד ‪ hexdigits .(9‬מכילה את כל הספרות בבסיס ‪ 0) 16‬עד ‪.(F‬‬
‫‪ octdigits‬מכילה את כל הספרות בבסיס ‪ 0) 8‬עד ‪ whitespace .(7‬מכילה את כל התווים שנחשבים כרווח )תו רווח‪ ,‬טאב‪,‬‬
‫מעבר שורה וכו'(‪ punctuation .‬מכילה את כל תווי הניקוד‪.‬‬

‫המודול ‪math‬‬
‫מודול זה מכיל מספר פונקציות שימושיות וקבועים לשימושים מתמטיים‪ ,‬כמו חישובים עם ‪ π‬או ‪ ,℮‬או משחקים משונים‬
‫עם מספרי נקודה‪-‬עשרונית‪.‬‬

‫‪ pi‬ו‪ e-‬הם שני קבועים המייצגים את ‪ π‬ואת ‪ ℮‬בדיוק של ‪ 11‬ספרות אחרי הנקודה‪.‬‬

‫הפונקציה ‪ ceil‬מקבלת מספר עשרוני ומעגלת אותו כלפי מעלה‪ floor .‬מקבלת מספר ומעגלת אותו כלפי מטה )מקצצת‬
‫את החלק העשרוני(‪.‬‬

‫הפונקציות ‪ cos ,sin‬ו‪ tan-‬הן כמובן שלוש הפונקציות הטריגונומטריות האהובות‪ ,‬ו‪ acos ,asin-‬ו‪ atan-‬הן הפונקציות‬
‫ההופכיות להן‪.‬‬

‫שאר הפונקציות מ‪ math-‬די טריוויאליות‪ ,‬וניתן פשוט לרפרף עליהן ע"י הסתכלות במחרוזת התיעוד )__‪ (__doc‬של כ"א‬
‫מהן‪.‬‬

‫המודול ‪time‬‬
‫בלי הרבה הפתעות‪ ,‬המודול ‪ time‬מכיל פונקציות לטיפול בזמן‪ .‬הפונקציה הפשוטה ביותר שקיימת במודול זה היא‬
‫)(‪ ,time‬שמחזירה את הזמן הנוכחי‪ .‬הזמן מוחזר במשתנה מסוג ‪ ,float‬והוא מייצג את מספר השניות שעברו מאז ‪1.1.1970‬‬
‫בחצות‪.‬‬
‫פונקציה שימושית נוספת במודול היא )(‪ ,sleep‬שמקבלת מספר שניות כ‪ float-‬ומשהה את התוכנית לפרק הזמן הזה‪.‬‬
‫שאר הפונקציות במודול משמשות לטיפול ולהדפסה של זמנים בצורות נוחות לבני אדם וכן לטיפול ב‪.Time Zones-‬‬

‫המודול ‪random‬‬
‫מודול זה מכיל פונקציות ליצירה של מספרים אקראיים‪ .‬הפונקציה שהכי דומה לפונקציות מקבילות מ‪ C-‬היא )(‪,random‬‬
‫שמחזירה מספר אקראי מסוג ‪ float‬בין ‪ 0.0‬ל‪.1.0-‬‬
‫אבל זה לא נוח במיוחד‪ ...‬בכלל זה הוסיפו עוד פונקציות נוחות במיוחד‪ ,‬לדוגמה )(‪ ,randrange‬שמחזירה מספר אקראי‬
‫בתחום מסוים‪:‬‬
‫‪>>> import random‬‬
‫)‪>>> random.randrange(3, 90‬‬
‫‪47‬‬

‫ואם זה לא מספיק‪ ,‬יש גם פונקציה שבוחרת איזשהו איבר אקראי מרשימה‪:‬‬


‫)]’‪>>> random.choice([‘a’, ‘b’, ‘c‬‬
‫’‪‘c‬‬

‫וכן גם יש פונקציה בשם )(‪ shuffle‬שמקבלת רשימה ומבלגנת את הסדר של האיברים שלה‪.‬‬

‫עמוד ‪35‬‬
‫‪Python 2.5‬‬

‫פרק ‪_:10‬מחלקות וירושה‬


‫מושגי יסוד‬
‫עולם המושגים של תכנות מבני )התכנות הישן והטוב‪ ,‬לדוגמה ‪ (C‬שונה מזה של תכנות מונחה עצמים )‪ ,OOP‬לדוגמה‬
‫‪ ,(C++‬ולפני שנעסוק במחלקות ב‪ ,Python-‬נסקור את המושגים בהם נשתמש בפרק זה‪ ,‬ובכלל בשימוש באובייקטים‪.‬‬

‫בתכנות מבני היו לנו מודולים‪ .‬מודול בדרך‪-‬כלל הכיל איזשהו טיפוס נתונים מופשט‪ ,‬כאשר מטרת המודול הייתה‬
‫לאפשר למשתמש ליצור ולטפל בטיפוס זה‪ .‬דוגמה למודול כזה הוא מודול רשימה‪ ,‬כאשר יש טיפוס של רשימה‪,‬‬
‫ופונקציות שונות )אתחול רשימה‪ ,‬הרס רשימה‪ ,‬הוספת איבר‪ ,‬חיפוש איבר‪ ,‬וכד'(‪ .‬לרוב‪ ,‬כדי שלפונקציות יהיו שמות‬
‫משמעותיים וכדי שלא יהיו התנגשויות בין שמות ממודולים שונים‪ ,‬לכל פונקציה היינו מוסיפים קידומת של שם המודול‬
‫)במקרה של רשימה הפונקציות היו נקראת ‪ ,list_add ,list_init‬וכו'(‪.‬‬
‫בתכנות מונחה עצמים יש לנו עצמים‪ .‬עצם בעולם התכנות הוא חיה שמייצגת איזשהו עצם במציאות‪ .‬הכוונה במייצג‬
‫היא שהעצם מכיל בתוכו מידע שמתאר עצם מסוים )בין אם העצם מוחשי או מופשט(‪ ,‬ובדומה לטיפוס הנתונים‬
‫המופשט מהמודול‪ ,‬העצם מכיל בתוכו פעולות אותן ניתן להפעיל על העצם‪ .‬המידע שמאפיין את העצם נקרא תכונות‬
‫)‪ ,(Properties‬והפעולות שניתן להפעיל על העצם נקראות מתודות )‪ .(Methods‬כאשר יוצרים עותק של עצם )כלומר‬
‫מקום בזיכרון בו יאוחסנו התכונות של עצם מסוים(‪ ,‬הדבר נקרא ‪) Instance‬מופע בעברית(‪ Instance .‬הוא ייצוג של‬
‫עצם בודד בזיכרון‪.‬‬

‫כמו כן‪ ,‬לעצם יש מתודות מיוחדות שנקראות בעת הבניה )‪ (Construction‬וההריסה )‪ (Destruction‬של העצם‪ .‬המתודה‬
‫שנקראת בעת הבניה מכונה בנאי )‪ ,Constructor‬או בקיצור ‪ ,(Ctor‬והמתודה שנקראת בעת ההריסה מכונה הורס‬
‫)‪ ,Destructor‬או בקיצור ‪.(Dtor‬‬

‫‪ Python‬ו‪OOP-‬‬
‫‪ Python‬היא שפה מונחית‪-‬אובייקטים‪ .‬זה אומר ש‪ Python-‬תומכת בהגדרת ויצירת עצמים‪ ,‬וכן תומכת בירושה‬
‫ופולימורפיזם )בצורה מסוימת(‪ .‬כל המושגים האלה יובהרו בהמשך‪.‬‬
‫בנוסף‪ ,‬ב‪ Python-‬כל דבר הוא אובייקט )‪ .(Everything is an object‬כל מה שלמדנו עד עכשיו – מספרים‪ ,‬מחרוזות‪,‬‬
‫רשימות‪ ,‬מילונים‪ ,‬ספריות ומודולים‪ ,‬קבצים‪ ,‬וכו' – כל אלה מיוצגים ע"י עצמים‪ .‬כאשר משתמשים בפונקציה ‪,type‬‬
‫למעשה מקבלים את שם העצם‪:‬‬

‫)‪>>> type(0‬‬
‫>’‪<type ‘int‬‬
‫)’‪>>> type(‘abc‬‬
‫>’‪<type ‘str‬‬

‫כאשר יוצרים מופעים חדשים של מחלקות‪ type ,‬מחזיר את הסוג ’‪ ‘instance‬עבורם‪ .‬בהמשך נראה למה זה ככה ומה‬
‫עושים עם זה‪.‬‬

‫הגדרת מחלקה‬
‫הגדרת מחלקה )תיאור של עצם( נעשית ע"י שימוש במילת המפתח ‪:class‬‬

‫‪>>> class A:‬‬


‫‪...‬‬ ‫‪def func(self):‬‬
‫‪...‬‬ ‫”‪print “The truth is out there‬‬

‫טוב‪ ,‬אז הדבר המוזר הזה זאת הגדרה של מחלקה חדשה‪ .‬שם המחלקה הוא ‪ .A‬בתוך המחלקה הכרזנו על מתודה בשם‬
‫‪ .func‬המתודה מקבלת פרמטר אחד בשם ‪) self‬מיד נראה בשביל מה צריך אותו( ומדפיסה הודעה למסך‪.‬‬
‫הפרמטר ‪ self‬הוא פרמטר שחייב להיות הפרמטר הראשון בכל מתודה במחלקה‪ self .‬הוא למעשה משתנה המכיל את‬
‫ה‪ Instance-‬עליו תורץ הפונקציה‪ ,‬כי אם נריץ "סתם פונקציה"‪ ,‬היא לא יכולה לדעת על איזה מופע עליה לפעול – כמו‬
‫שבתכנות מבני יכולות להיות כמה רשימות באותה התוכנית‪ ,‬כך בתכנות מונחה עצמים יכולים להיות כמה מופעים של‬
‫אותו העצם‪ .‬ב‪ C++-‬הדבר נעשה באמצעות ‪.this‬‬

‫אם כן‪ ,‬לכל מתודה במחלקה מועבר הפרמטר ‪ ,self‬והמשתמש יכול לשנות ולהוסיף תכונות למחלקה )דרך אגב‪,‬‬
‫הפרמטר הנ"ל לא חייב להיקרא ‪ ,self‬אך זה הרגל מקובל ומושרש בעולם הפיתוני‪ .(...‬דבר זה נעשה בדיוק כמו עם‬
‫משתנים רגילים‪ ,‬כלומר השמת ערך למשתנה שאינו קיים תיצור אותו ותאתחל אותו לערך זה‪:‬‬

‫‪>>> class A:‬‬


‫‪...‬‬ ‫‪def func1(self):‬‬
‫‪...‬‬ ‫‪self.prop1 = 17‬‬
‫‪...‬‬ ‫‪def func2(self):‬‬
‫‪...‬‬ ‫‪print self.prop1‬‬

‫המתודה ‪ func1‬מאתחלת משתנה בשם ‪ prop1‬להיות ‪ prop1 .17‬הוא מאפיין במופע ‪ self‬של ‪ .A‬המתודה ‪ func2‬מדפיסה‬
‫את ערך המאפיין ‪ prop1‬למסך‪.‬‬

‫עמוד ‪36‬‬
‫‪Python 2.5‬‬

‫בדיוק כאן מתעוררת בעיה – מה יקרה אם המשתמש במחלקה יפעיל את המתודה ‪ func2‬לפני ‪ – func1‬הרי אם ‪func1‬‬
‫לא הופעלה‪ prop1 ,‬לא נוצר‪ ,‬אז מה ‪ func2‬תדפיס? במקרה כזה תהיה שגיאה‪ ,‬משום ש‪ prop1-‬אכן לא קיים‪ ,‬והפנייה‬
‫אליו תהיה כמו פנייה למשתנה שלא נוצר מעולם‪.‬‬

‫בדיוק בשביל זה קיימות פונקציות הבנייה וההריסה של מחלקה‪ .‬פונקציות אלה )‪ Constructor‬ו‪ (Destructor-‬נועדו לרוץ‬
‫בעת יצירת המחלקה ובעת הרס המחלקה‪ .‬יצירת המחלקה תהיה ברגע שהמשתמש יוצר מופע חדש של המחלקה –‬
‫כלומר מובטח שפונקצית האתחול תרוץ לפני כל פונקציה אחרת במחלקה‪ .‬באותו האופן‪ ,‬כאשר מופע עומד להיהרס‬
‫)אם הוא היה משתנה זמני בפונקציה והיא הסתיימה‪ ,‬אם המשתמש מחק את ה‪ Instance-‬עם ‪ ,del‬וכו'( תורץ פונקצית‬
‫ההריסה‪ ,‬שתאפשר לבצע פעולות סיום למיניהן‪.‬‬
‫יש לציין שפונקציות הבנייה וההריסה לא נועדו רק לייצור משתנים פנימיים של מחלקה‪ ,‬אלא עבור אתחול מחלקה‪,‬‬
‫קריאה לפונקציות בנייה שונות‪ ,‬אתחול עצמים פנימיים‪ ,‬וכו'‪.‬‬
‫ב‪ ,Python-‬פונקצית היצירה נקראת __‪) __init‬שני קווים תחתונים לפני ואחרי המילה ‪ (init‬ופונקצית ההריסה נקראת‬
‫__‪ .__del‬הנה דוגמה למחלקה ‪ A‬אחרי הוספת פונקצית יצירה‪:‬‬

‫‪>>> class A:‬‬


‫‪...‬‬ ‫‪def __init__(self):‬‬
‫‪...‬‬ ‫‪self.prop1 = 17‬‬
‫‪...‬‬ ‫‪def func2(self):‬‬
‫‪...‬‬ ‫‪print self.prop1‬‬

‫וכעת‪ ,‬כאשר ייווצר מופע של ‪ ,A‬קודם כל תורץ הפונקציה __‪ ,__init‬ללא כל צורך לקרוא לה בצורה חיצונית‪ .‬בצורה‬
‫דומה‪ ,‬ניתן להוסיף מתודה בשם __‪ __del‬שתיקרא בעת הריסת מופע של ‪:A‬‬

‫‪>>> class A:‬‬


‫‪...‬‬ ‫‪def __init__(self):‬‬
‫‪...‬‬ ‫'!‪print 'Hello, World‬‬
‫‪...‬‬ ‫‪def __del__(self):‬‬
‫‪...‬‬ ‫'!‪print 'Goodbye, World‬‬
‫‪...‬‬ ‫‪def do_something(self):‬‬
‫‪...‬‬ ‫'!‪print 'Doing, Something‬‬
‫‪...‬‬
‫)(‪>>> a = A‬‬
‫!‪Hello, World‬‬
‫)(‪>>> a.do_something‬‬
‫!‪Doing, Something‬‬
‫‪>>> del a‬‬
‫!‪Goodbye, World‬‬

‫יש לשים לב שב ‪ ,Python‬לעתים קשה לחזות מתי בדיוק אובייקט ייהרס‪ Python .‬היא שפה המכונה בעגה המקצועית‬
‫"‪ ,"Garbage-Collected‬מה שאומר שהיא אחראית על הריסת אובייקטים בזמן המתאים ביותר להריסתם‪ ,‬מה שעלול‬
‫להיות אחרי פקודת ה ‪ del‬או אחרי הפסקת השימוש באובייקט‪.‬‬

‫בנוסף‪ ,‬יש להיזהר בעת השימוש בפונקציית __‪ – __del‬לרוב אין צורך בה‪ ,‬אבל אם משתמשים בה יש לוודא שבעת‬
‫השמדת המחלקה‪ ,‬לא תהיה פנייה למחלקות אחרות שכבר הושמדו )שכן רוב הפניות לפונקציית ההשמדה יהיו בעת‬
‫סיום תוכנית‪ ,‬שלב בו לפעמים לא ברור מהו סדר ההשמדה של עצמים(‪.‬‬

‫שימוש במחלקות שיצרנו‬


‫עד עכשיו סקרנו כיצד מגדירים מחלקה‪ .‬כעת נראה כיצד יוצרים מופעים של מחלקה‪:‬‬

‫‪>>> class A:‬‬


‫‪...‬‬ ‫‪def __init__(self, name, age):‬‬
‫‪...‬‬ ‫‪self.my_name = name‬‬
‫‪...‬‬ ‫‪self.my_age = age‬‬
‫‪...‬‬ ‫‪def get_name(self):‬‬
‫‪...‬‬ ‫‪return self.my_name‬‬
‫‪...‬‬ ‫‪def get_age(self):‬‬
‫‪...‬‬ ‫‪return self.mt_age‬‬
‫‪...‬‬
‫)‪>>> person = A(‘moshe’, 17‬‬

‫בדוגמה הגדרנו מחלקה בשם ‪ ,A‬כאשר פונקצית היצירה שלה מקבלת ‪ 3‬פרמטרים – ‪ self‬אותו חובה לקבל בכל מתודה‪,‬‬
‫‪ name‬ו‪ .age-‬פונקצית היצירה יוצרת את ‪ self.my_name‬ואת ‪ self.my_age‬ומכניסה לתוכם את הערכים הנ"ל‪ .‬כמו כן‪,‬‬
‫המחלקה כוללת שתי מתודות לקבלת ‪ name‬ו‪.age-‬‬

‫יצירת המחלקה מתבצעת בשורה האחרונה‪ ,‬כאשר משתנה בשם ‪ person‬מקבל את ה‪ Instance-‬של המחלקה החדשה‬
‫שנוצרת‪.‬‬

‫עמוד ‪37‬‬
‫‪Python 2.5‬‬

‫המחלקה נוצרת ע"י כתיבת שם המחלקה ‪ ,A‬ואחריה סוגריים‪ .‬בסוגריים נרשמים כל הפרמטרים שיועברו לאחר מכן ל‪-‬‬
‫__‪ ,__init‬לפי הסדר‪ ,‬ולאחר הפרמטר ‪ .self‬כמובן שאין צורך לרשום את ‪ ,self‬הוא נמצא רק במימוש הפנימי של‬
‫המחלקה‪ ,‬ואינו מוכר מחוץ אליה‪.‬‬

‫הפרמטרים שיועברו ל‪ __init__-‬הם‪ name :‬יהיה ’‪ ‘moshe‬ו‪ age-‬יהיה ‪.17‬‬

‫הנה כמה דוגמאות לשימוש במופע שנוצר‪:‬‬

‫)(‪>>> person.get_name‬‬
‫’‪‘moshe‬‬
‫)(‪>>> person.get_age‬‬
‫‪17‬‬
‫‪>>> person.my_age‬‬
‫‪17‬‬
‫‪>>> person.my_name‬‬
‫’‪‘moshe‬‬

‫כפי שניתן לראות‪ ,‬הפעלת מתודה של ה‪ Instance-‬היא כתיבת שם המשתנה המכיל את ה‪ ,Instance-‬נקודה‪ ,‬שם‬
‫המתודה‪ ,‬וסוגריים הכוללים את הפרמטרים למתודה )בדוגמה אין שום פרמטרים למתודות(‪.‬‬
‫כמו כן‪ ,‬המאפיינים ‪ my_age‬ו‪ my_name-‬של המחלקה זמינים בדיוק כמו ב‪ struct-‬של ‪ .C‬מרגע שהם נוצרו בתוך‬
‫המחלקה‪ ,‬ניתן לקרוא ולשנות אותם גם מחוץ למחלקה‪ .‬בהמשך נראה כיצד מחביאים מאפיינים של מחלקה כך שיהיו‬
‫זמינים רק למתודות של המחלקה‪.‬‬

‫בדוגמה האחרונה ראינו כיצד ניתן ליצור מופעים של מחלקות ולהריץ מתודות שלהם – מספקים משתנה המכיל את ה‪-‬‬
‫‪ ,Instance‬וקוראים למתודה שנמצאת בתוכו‪ .‬דרך נוספת להריץ מתודה של מחלקה על מופע מסוים היא קריאה ישירה‬
‫למתודה של המחלקה )כלומר‪ ,‬שימוש בשם המחלקה ולא בשם ה‪ ,(Instance-‬תוך העברת פרמטר המכיל מופע‪:‬‬

‫)‪>>> A.get_name(person‬‬
‫’‪‘moshe‬‬

‫בדרך זו העברנו למעשה את ‪ person‬כפרמטר ‪ self‬בצורה מפורשת‪ .‬דרך קריאה זו אמנם פחות יפה‪ ,‬אבל יש לה‬
‫שימושים‪ ,‬בעיקר כאשר יש צורך להשתמש ב‪ reduce ,map-‬או ‪ .filter‬לדוגמה‪ ,‬ניצור רשימה ובה ‪ 5‬מופעים של ‪ .A‬לאחר‬
‫מכן ניצור רשימה ובה רק שדות ה‪ my_name-‬של המחלקה‪:‬‬

‫])‪>>> people = [A(‘moshe’, 17), A(‘haim’, 34), A(‘igor’, 51), A(‘amir’, 21), A(‘x’, 68‬‬
‫)‪>>> map(A.get_name, people‬‬
‫]’‪[‘moshe’, ‘haim’, ‘igor’, ‘amir’, ‘x‬‬

‫לגבי מתודות בתוך מחלקה‪ ,‬אין הגבלות על קריאות של מתודות אחת לשניה‪ ,‬רקורסיה של מתודה וכד'‪ .‬בנוסף‪ ,‬היתרון‬
‫ב‪ Python-‬הוא שמתודה אחת יכולה לקרוא למתודה אחרת שעדיין לא הוגדרה‪ .‬דבר זה אפשרי בגלל שהרצת המתודה‬
‫תתבצע ע"י ה‪ Interpreter-‬רק לאחר שכל הפונקציות כבר הוגדרו‪ ,‬ולכן הפונקציה שהוגדרה "מאוחר יותר" תהיה זמינה‬
‫)ב‪ C-‬היה צורך לשנות את סדר הפונקציות או ליצור ‪-prototype‬ים לפונקציות(‪:‬‬

‫‪>>> class B:‬‬


‫‪...‬‬ ‫‪def func1(self):‬‬
‫‪...‬‬ ‫)(‪self.func2‬‬
‫‪...‬‬ ‫‪def func2(self):‬‬
‫‪...‬‬ ‫”‪print “It works‬‬
‫אחד הדברים שמייחדים מתודות מפונקציות רגילות )וגם מוסיפים עוד כוח למודל האובייקטים של ‪ (Python‬הוא מושג ה‬
‫‪ .bound-methods‬לא נעמיק כאן בצורה בה הדבר ממומש‪ ,‬אך יש לשים לב שהקוד הבא אפשרי ב ‪:Python‬‬

‫‪>>> class A:‬‬


‫‪...‬‬ ‫‪def __init__(self, i):‬‬
‫‪...‬‬ ‫‪self.member = i‬‬
‫‪...‬‬ ‫‪def print_member(self):‬‬
‫‪...‬‬ ‫‪print self.member‬‬
‫‪...‬‬
‫)‪>>> a_instance = A(17‬‬
‫‪>>> f = a_instance.print_member‬‬
‫)(‪>>> f‬‬
‫‪17‬‬
‫שים לב שקראנו למתודה של אובייקט לכאורה ללא האובייקט עצמו‪ .‬ב ‪ Python‬הדבר אפשר כיוון שמתודות של‬
‫מופעים "זוכרות" לאיזה מופע הן שייכות‪.‬‬

‫עמוד ‪38‬‬
‫‪Python 2.5‬‬

‫הסתרת איברים במחלקה‬


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

‫‪ Python‬מספקת מנגנון להחבאת משתנים פנימיים ומתודות פנימיות של המחלקה כך שהמתכנת מציין אילו מתודות‬
‫ומאפיינים הוא מעוניין להחביא‪ ,‬ו‪ Python-‬משנה את השם המקורי של כ"א מהאיברים להחבאה לשם אחר‪ .‬כאשר נעשה‬
‫שימוש באחד מהשמות ה"מוחבאים"‪ Python ,‬פונה לשם האחר‪.‬‬
‫השמות האחרים הללו אמנם נגישים מבחוץ‪ ,‬אבל הם לא קבועים ויכולים להשתנות ממימוש למימוש‪ ,‬ולכן לא ניתן‬
‫לפנות אליהם בצורה חד‪-‬משמעית‪ .‬דבר זה מבטיח הגנה מסוימת מטעויות שעלולות להתבצע בשוגג‪ .‬מצד שני‪ ,‬אם‬
‫משתמש מעונין לשנות משתנים פנימיים של מחלקה מסוימת‪ ,‬אין שום קושי לבצע ‪ dir‬על מחלקה ולראות אילו משתנים‬
‫קיימים בתוכה )ואולי להבין מי מהם הוא המשתנה שהוא מחפש(‪.‬‬

‫החבאת משתנים או מתודות נעשית ע"י הכנסת שני קווים תחתונים לפני השם שלהם‪ .‬בכל פנייה למשתנים או מתודות‬
‫אלו יש לציין את השם עם הקווים התחתונים )הם חלק מהשם‪ ,‬ולא תוספת חד‪-‬פעמית שמציינת החבאה(‪:‬‬

‫‪>>> class C:‬‬


‫‪...‬‬ ‫‪def __init__(self):‬‬
‫‪...‬‬ ‫‪self.__a = 0‬‬
‫‪...‬‬ ‫‪self.__b = 0‬‬
‫‪...‬‬ ‫‪self.__c = 0‬‬
‫‪...‬‬ ‫‪def get_a(self):‬‬
‫‪...‬‬ ‫‪return self.__a‬‬
‫‪...‬‬ ‫‪def set_a(self, new_a):‬‬
‫‪...‬‬ ‫‪self.__a = new_a‬‬
‫‪...‬‬ ‫‪def get_b(self):‬‬
‫‪...‬‬ ‫‪return self.__b‬‬
‫‪...‬‬ ‫‪def set_b(self, new_b):‬‬
‫‪...‬‬ ‫‪self.__b = new_b‬‬
‫‪...‬‬ ‫‪def get_c(self):‬‬
‫‪...‬‬ ‫‪return self.__c‬‬
‫‪...‬‬ ‫‪def set_c(self, new_c):‬‬
‫‪...‬‬ ‫‪self.__c = new_c‬‬
‫‪...‬‬
‫)(‪>>> e = C‬‬
‫‪>>> e.__a‬‬
‫‪Traceback (most recent call last):‬‬
‫? ‪File "<stdin>", line 1, in‬‬
‫’‪AttributeError: C instance has no attribute ‘__a‬‬
‫)(‪>>> e.get_a‬‬
‫‪0‬‬

‫כפי שניתן לראות‪ ,‬לא ניתן היה לגשת למאפיין ‪ __a‬של ‪ ,C‬כי הוא מוחבא‪ ,‬אבל ניתן בהחלט לראות את הערך שלו ע"י‬
‫שימוש במתודה ‪ get_a‬שיכולה לגשת למאפיין )כי היא בתוך המחלקה(‪.‬‬

‫למעשה‪ ,‬ההחבאה אינה החבאה מוחלטת‪ ,‬אלא הוספת שם המחלקה‪ ,‬בתוספת מספר קווים‪-‬תחתונים‪ ,‬לשם המשתנה‪.‬‬
‫בצורה הזו לא ניתן לגשת למשתנה בצורה טריוויאלית )צריך "לעבוד קצת" כדי להשיג את המשתנה(‪.‬‬
‫מטרת ה"החבאה" היא לא החבאה מושלמת – מטרתה היא להבהיר שמשתנים מוחבאים הם משתנים פנימיים שלא‬
‫מומלץ לגעת בהם‪.‬‬
‫דוגמה לשם משתנה לאחר ההחבאה שלו‪:‬‬

‫‪>>> class A:‬‬


‫‪...‬‬ ‫‪def __init__(self):‬‬
‫‪...‬‬ ‫‪self.__x = 1‬‬
‫‪...‬‬
‫)(‪>>> a = A‬‬
‫)‪>>> dir(a‬‬
‫]'__‪['_A__x', '__doc__', '__init__', '__module‬‬

‫כפי שניתן לראות‪ ,‬בתוך ‪ a‬יש משתנה בשם ‪ ,_A__x‬והוא למעשה המשתנה הפנימי ‪.__x‬‬

‫ירושה‬
‫עד עכשיו ראינו כיצד ניתן ליצור מחלקות‪ ,‬להגדיר מתודות למחלקות אלה‪ ,‬וליצור מופעים של מחלקות‪ .‬כל אלה‬
‫מאפשרים לאגד את כל התכונות והפעולות של עצם מסוים בטיפוס אחד ולגשת אליו בצורה נוחה‪.‬‬
‫אבל‪ ,‬מה קורה אם נרצה לקחת עצם קיים ולהרחיב אותו? כלומר‪ ,‬לקחת מחלקה ולהוסיף לה מספר מתודות‪ ,‬כדי‬
‫להפוך אותה לעצם "משוכלל יותר"‪ .‬דרך אפשרית היא לפתוח את קוד המקור של המחלקה ולשנות את המחלקה‬
‫עצמה כך שתכיל את כל המתודות החדשות שנרצה בנוסף לאלו שכבר קיימות‪ .‬אמנם בדרך זו נקבל את התוצאה‬

‫עמוד ‪39‬‬
‫‪Python 2.5‬‬

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

‫הפתרון לכל הבעיות האלה הוא ירושה )‪ .(Inheritance‬ירושה היא לקיחת מחלקה קיימת‪ ,‬ושימוש בה ליצירת מחלקה‬
‫חדשה‪ .‬ההבדל בין ירושה לבין הפתרון הקודם לבעיית השימוש במחלקה קיימת הוא שבירושה אין העתקה של קוד‪,‬‬
‫אלא שימוש בקוד קיים‪.‬‬

‫בירושה יש מחלקת אב )‪ (Parent Class‬ומחלקת בן )‪ .(Sub Class‬מחלקת האב היא המחלקה ממנה יורשים‪ ,‬כלומר‬
‫המחלקה ממנה לוקחים את כל המאפיינים והמתודות הקיימות‪ .‬מחלקת הבן היא המחלקה החדשה שנוצרת ממחלקת‬
‫האב וכוללת את המתודות והמאפיינים הנוספים למחלקת האב‪.‬‬
‫כאשר מגדירים את מחלקת הבן‪ ,‬אין צורך לממש )ואפילו אין צורך להגדיר( את המתודות ממחלקת האב – מעצם‬
‫העובדה שמחלקת הבן יורשת ממחלקת האב‪ ,‬כל המתודות של מחלקת האב מובאות לתוך מחלקת הבן‪.‬‬

‫לדוגמה‪ ,‬הנה מחלקת האב ממנה נירש‪:‬‬

‫‪>>> class Animal:‬‬


‫‪...‬‬ ‫‪def __init__(self):‬‬
‫‪...‬‬ ‫‪self.age = 0‬‬
‫‪...‬‬ ‫‪self.hunger = 10‬‬
‫‪...‬‬ ‫‪self.fun = 0‬‬
‫‪...‬‬ ‫‪def grow(self):‬‬
‫‪...‬‬ ‫‪self.age += 1‬‬
‫‪...‬‬ ‫‪def eat(self):‬‬
‫‪...‬‬ ‫‪if self.hunger > 0:‬‬
‫‪...‬‬ ‫‪self.hunger -= 1‬‬
‫‪...‬‬ ‫‪def play(self):‬‬
‫‪...‬‬ ‫‪self.fun += 1‬‬
‫‪...‬‬ ‫‪def go_to_toilet(self):‬‬
‫‪...‬‬ ‫‪self.hunger += 1‬‬
‫‪...‬‬ ‫‪def sleep(self):‬‬
‫‪...‬‬ ‫‪self.fun -= 1‬‬

‫המחלקה מייצגת חיה‪ ,‬כאשר החיה יכולה לגדול‪ ,‬לאכול‪ ,‬לשחק‪ ,‬ללכת לשירותים ולישון‪.‬‬
‫הקוד הבא מגדיר מחלקה בשם ‪ ,Dog‬שיורשת מ‪ Animal-‬ומכילה מתודות חדשות‪:‬‬

‫‪>>> class Dog(Animal):‬‬


‫‪...‬‬ ‫‪def __init__(self):‬‬
‫‪...‬‬ ‫)‪Animal.__init__(self‬‬
‫‪...‬‬ ‫‪def bark(self):‬‬
‫‪...‬‬ ‫'‪print 'Waff Waff‬‬
‫‪...‬‬ ‫‪def wag_tail(self):‬‬
‫‪...‬‬ ‫‪self.fun += 2‬‬
‫‪...‬‬ ‫'‪print 'Wagging‬‬

‫המחלקה ‪ Dog‬יורשת ממחלקת ‪ ,Animal‬ובנוסף לכל המתודות ש‪ Animal-‬מגדירה‪ Dog ,‬מכילה ‪ 2‬מתודות חדשות –‬
‫מתודה לנביחה ומתודה לכשכוש בזנב‪.‬‬
‫יש לשים לב שבמתודת ה‪ __init__-‬של ‪ Dog‬יש קריאה למתודת ה‪ __init__-‬של ‪ .Animal‬דבר זה נעשה כדי לאפשר ל‪-‬‬
‫‪ Animal‬לאתחל את כל המאפיינים שקשורים אליו‪ .‬קריאה זו לא נעשית אוטומטית )שלא כמו ב‪ ,(C++-‬ויש לציין אותה‬
‫במפורש‪.‬‬
‫שימוש במחלקה החדשה ‪ Dog‬הוא בדיוק כמו שימוש במחלקה רגילה‪:‬‬

‫)(‪>>> dog = Dog‬‬


‫)(‪>>> dog.play‬‬
‫)(‪>>> dog.bark‬‬
‫‪Waff Waff‬‬
‫)(‪>>> dog.wag_tail‬‬
‫‪Wagging‬‬
‫)(‪>>> dog.eat‬‬
‫)(‪>>> dog.sleep‬‬
‫‪>>> dog.fun, dog.hunger, dog.age‬‬
‫)‪(2, 9, 0‬‬

‫בנוסף להגדרת מתודות נוספות במחלקה )כאלה שמרחיבות את המחלקה הקיימת(‪ ,‬ניתן ליצור מתודות שמחליפות‬
‫מתודות במחלקת האב‪ .‬כלומר‪ ,‬אם נרצה נוכל ליצור מתודה במחלקה ‪ ,Dog‬כך שכאשר עובדים עם מופעים של ‪,Dog‬‬
‫במקום לקרוא לפונקציה מסוימת ב‪ ,Animal-‬קוראים לפונקציה אחרת ב‪.Dog-‬‬

‫עמוד ‪40‬‬
‫‪Python 2.5‬‬

‫דבר זה נעשה ע"י יצירת פונקציה בעלת אותו שם כמו ב‪ ,Animal-‬שתהיה ממומשת ב‪ .Dog-‬לדוגמה‪ ,‬הנה הגדרה אחרת‬
‫של ‪ ,Dog‬כאשר יש בה החלפה של המתודה ‪ grow‬מ‪ Animal-‬במתודה חדשה של עצמים מסוג ‪:Dog‬‬

‫‪>>> class Dog(Animal):‬‬


‫‪...‬‬ ‫‪def __init__(self):‬‬
‫‪...‬‬ ‫)‪Animal.__init__(self‬‬
‫‪...‬‬ ‫‪def bark(self):‬‬
‫‪...‬‬ ‫'‪print 'Waff Waff‬‬
‫‪...‬‬ ‫‪def wag_tail(self):‬‬
‫‪...‬‬ ‫‪self.func += 2‬‬
‫‪...‬‬ ‫'‪print 'Wagging‬‬
‫‪...‬‬ ‫‪def grow(self):‬‬
‫‪...‬‬ ‫‪self.age += 10‬‬

‫כעת‪ ,‬כאשר נקרא למתודה ‪ ,grow‬תיקרא המתודה מ‪ ,Dog-‬ולא מ‪ :Animal-‬סדר החיפוש של מתודות הוא מהמחלקה‬
‫ה"חדשה" ביותר‪ ,‬כלומר ‪ Python‬תחפש קודם את המתודה במחלקת הבן‪ ,‬ורק אחר כך במחלקת האב‪ .‬אם יש שרשרת‬
‫של ירושות )כלומר‪ ,‬מחלקת האב היא מחלקת בן בעצמה(‪ ,‬החיפוש יתבצע שוב ושוב עד שלא יהיה איפה לחפש או עד‬
‫שתימצא מתודה בשם המבוקש‪.‬‬

‫נושא נוסף שקשור לירושה הוא ירושה מרובה‪ .‬נושא זה לא יילמד במסגרת חוברת זו‪.‬‬

‫איך כל זה משתלב עם מה שלמדנו עד כה‬


‫פרק זה סקר את נושא המחלקות ב‪ .Python-‬למעשה‪ ,‬ב‪ Python-‬כל דבר הוא עצם‪ ,‬אפילו טיפוסי הנתונים הבסיסיים‪:‬‬
‫רשימה‪ ,‬מילון‪ ,Tuple ,‬מחרוזות – כל אלה מחלקות‪ .‬בגירסאות מתקדמות של ‪ Python‬ניתן ליצור ירושה כאשר מחלקת‬
‫האב היא אחד מהטיפוסים הבסיסיים‪ ,‬ועל‪-‬ידי כך ליצור טיפוסים חדשים‪.‬‬

‫בנוסף‪ ,‬המודולים שמסופקים עם ‪ Python‬מכילים אף הם הרבה מאוד מחלקות מוכנות לשימוש‪ .‬מחלקות אלה יכולות‬
‫לחסוף הרבה זמן בשימוש בהן‪ ,‬או בירושה מהן כדי ליצור מחלקה מותאמת אישית‪ .‬מומלץ להיעזר בתיעוד ולסקור את‬
‫המחלקות הקיימות‪.‬‬

‫עמוד ‪41‬‬
‫‪Python 2.5‬‬

‫פרק ‪Exceptions _:11‬‬


‫מה זה ‪-Exception‬ים?‬
‫‪ Exceptions‬זוהי דרך לטיפול בשגיאות בה אין בדיקת ערך החזרה מפונקציות‪ ,‬אלא הגדרת קטעי קוד שמתבצעים‬
‫במקרה שמתרחשת שגיאה‪.‬‬

‫דמיינו לעצמם שהתוכנית שלכם יודעת לבד מתי יש שגיאה‪ ,‬ואתם יכולים להגיד לתוכנית שתבצע רצף פעולות מסוים‪,‬‬
‫כאשר אתם גם אומרים לה מה לעשות אם תהיה שגיאה‪ .‬בצורה כזו‪ ,‬ניתן לכתוב תוכניות הרבה יותר פשוטות‪ ,‬כי אין‬
‫צורך לבדוק כל הזמן ערכי החזרה מפונקציות ואין צורך לטפל בכל שגיאה בנפרד – התוכנית יודעת לבד מתי יש‬
‫שגיאה‪ ,‬והיא יודעת מה לעשות אם יש שגיאה‪.‬‬
‫זוהי בדיוק דרך הפעולה של ‪) Exceptions‬חריגות בעברית(‪ .‬ב‪ Exceptions-‬המשתמש מגדיר קטעי קוד‪ ,‬אותם הוא תוחם‬
‫בצורה מיוחדת כדי שניתן יהיה לדעת בדיוק על איזה קטע קוד עובדים עכשיו‪ .‬בנוסף‪ ,‬המשתמש מגדיר לכל קטע קוד‬
‫כזה קטע של טיפול בשגיאות – זהו קוד נוסף שיתבצע אם תהיה שגיאה‪ .‬ניתן לכתוב כמה קטעי קוד לטיפול בשגיאות‪,‬‬
‫אחד לכל סוג שגיאה משלו‪.‬‬

‫ב‪ Exceptions-‬יש שלושה מושגים מרכזיים‪:‬‬


‫• ‪) try‬ניסיון( – פעולה זו היא הרצת קטע הקוד שיש להפעיל‪ ,‬כלומר הקוד של התוכנית הרגילה‪.‬‬
‫• ‪) throw‬זריקה( – פעולה זו מתרחשת כאשר יש שגיאה בתוך קטע הקוד של ה‪ .try-‬פעולת הזריקה היא למעשה‬
‫יצירת שגיאה ושליחתה לטיפול בקטעי טיפול השגיאות‪ .‬השגיאה שנזרקה יכולה להיות בכל מקום בקוד ה‪ ,try-‬גם‬
‫בתוך פונקציה שקוד ה‪ try-‬קרא לה‪ .‬לכן‪ ,‬השגיאה מפעפעת עד שהיא מוצאת קטע קוד לטיפול בשגיאה‪.‬‬
‫• ‪) catch‬תפיסה( – זוהי הפעולה בה קטע קוד לטיפול בשגיאה תפס את השגיאה והוא מטפל בה‪ .‬קטע הקוד שתפס‬
‫את השגיאה רשאי לזרוק אותה שוב )לתת לה להמשיך לפעפע בכל קטעי הקוד שקראו לה(‪ ,‬ואף לזרוק שגיאה‬
‫אחרת‪.‬‬

‫ב‪ ,Python-‬כאשר יוצרים קוד ששיטת הטיפול בשגיאות בו היא ע"י ‪ ,Exceptions‬כותבים קטעי קוד לניסיון בבלוקים‬
‫שנקראים ‪ .try‬מיד אחרי כל בלוק ‪ ,try‬יופיע לפחות בלוק ‪ except‬אחד‪ .‬בלוק ‪ except‬הוא בלוק התפיסה‪ ,‬כאשר הוא‬
‫כולל פרמטר המציין את סוג השגיאה )מיד נראה מה זה סוג שגיאה(‪ .‬זריקה מתבצעת ע"י הפקודה ‪ ,raise‬שמקבלת‬
‫כפרמטר את סוג השגיאה שיש לזרוק‪.‬‬

‫לדוגמה‪ ,‬קטע הקוד הבא מתבצע עד שפקודת ה‪ raise-‬מתרחשת‪ .‬ברגע שמדיעים לפקודת ה‪ ,raise-‬השליטה עוברת‬
‫לבלוק ה‪ except-‬המתאים‪:‬‬

‫‪>>> try:‬‬ ‫מקטע ה‪try-‬‬


‫‪...‬‬ ‫'‪print 'Hello‬‬ ‫מתחיל לרוץ‪...‬‬
‫‪...‬‬ ‫'‪print 'World‬‬
‫‪...‬‬ ‫'‪print 'My‬‬
‫‪...‬‬ ‫'‪print 'Name‬‬ ‫נזרקת שגיאה והשליטה‬
‫‪...‬‬ ‫)(‪raise Error2‬‬ ‫עוברת מיד לקטע הקוד‬
‫‪...‬‬ ‫'‪print 'Is‬‬ ‫המתאים‪.‬‬
‫‪...‬‬ ‫'‪print 'Luca‬‬
‫‪... except Error1:‬‬
‫‪...‬‬ ‫'‪print 'Error #1 has occured‬‬
‫‪... except Error2:‬‬
‫‪...‬‬ ‫'‪print 'Error #2 has occured‬‬
‫‪... except Error3:‬‬
‫‪...‬‬ ‫'‪print 'Error #3 has occured‬‬
‫‪...‬‬
‫‪Hello‬‬
‫‪World‬‬
‫‪My‬‬
‫‪Name‬‬
‫‪Error #2 has occured‬‬

‫ואכן‪ ,‬השגיאה שנזרקה הייתה מסוג ‪ ,Error2‬וקטע ה‪ except-‬המתאים התבצע‪ .‬יש לציין שכמו שהתבצעה זריקה מתוך‬
‫מקטע ה‪ ,try-‬כך גם יכולה להתבצע זריקה מתוך פונקציות שקטע ה‪ try-‬קרא לה‪ ,‬או מתוך פונקציה שהפונקציה שקטע‬
‫ה‪ try-‬קרא לה‪ ,‬וכו'‪ .‬כלומר‪ ,‬אי‪-‬אפשר לדעת מאיפה בתוך הקטע תיזרק השגיאה‪.‬‬

‫אז מה זאת השגיאה ‪ ,Error2‬או ליתר דיוק מה זה אומר שגיאה מסוג ‪ ?Error2‬התשובה דווקא פשוט – שגיאה היא כל‬
‫אובייקט שיורש מהמחלקה ‪.Exception‬‬
‫המחלקה ‪ Exception‬היא מחלקה מובנית בשפה‪ ,‬וכל ה‪Exception-‬ים חייבים לרשת ממנה‪ .‬קיימים כל‪-‬מיני ‪Exception‬ים‬
‫שכבר ראינו לאורך החוברת‪ ,‬אך לא התייחסנו אליהם‪ ,‬כמו ‪ SyntaxError‬או ‪ .TypeError‬שני ‪Exception‬ים אלה‪ ,‬ועוד‬
‫הרבה אחרים‪ ,‬הם ‪Exception‬ים מובנים ב‪ Python-‬שנזרקים עלינו בתגובה לדברים רעים שאנחנו עושים בשפה או‬
‫במנגנונים מובנים שלה‪.‬‬

‫עמוד ‪42‬‬
‫‪Python 2.5‬‬

‫‪ Python‬מאפשרת לנו ליצור ‪Exception‬ים חדשים משלנו‪ ,‬כדי שנוכל לציין במפורש שגיאות שלנו‪ ,‬מבלי להשתמש‬
‫בשגיאות קיימות‪ .‬כך נוכל לוודא שאנחנו תופסים ומטפלים בשגיאה הנכונה‪ ,‬אם היא תיזרק‪.‬‬
‫לדוגמה‪ ,‬ניצור ‪ Exception‬חדש ונשתמש בו בפונקציה )(‪:f‬‬

‫‪>>> class BadThingHappened(Exception):‬‬


‫‪...‬‬ ‫‪pass‬‬
‫‪...‬‬
‫‪>>> def f(a):‬‬
‫‪...‬‬ ‫‪if a != 'please do not fail':‬‬
‫‪...‬‬ ‫‪raise BadThingHappened‬‬
‫‪...‬‬
‫)‪>>> f(3‬‬
‫‪Traceback (most recent call last):‬‬
‫>‪File "<stdin>", line 1, in <module‬‬
‫‪File "<stdin>", line 3, in f‬‬
‫‪__main__.BadThingHappened‬‬

‫אם נרצה לתפוס את השגיאה שיצרנו‪ ,‬נוכל לעטוף את הקריאה ל‪ f()-‬בבלוק ‪:try…except‬‬

‫‪>>> try:‬‬
‫‪...‬‬ ‫)‪f(3‬‬
‫‪... except BadThingHappened:‬‬
‫‪...‬‬ ‫'‪print 'everything is ok‬‬
‫‪...‬‬
‫‪everything is ok‬‬

‫הדוגמה האחרונה הייתה פשוטה‪ ,‬אך כמובן חסרת כל שימוש‪ .‬כעת נראה דוגמה לשימוש אמיתי ב‪Exception-‬ים‪ ,‬ולצורך‬
‫כך נכתוב פונקציה שמוחקת קובץ‪ .‬הפונקציה תקרא ל‪ ,os.remove-‬ואם תקרה שגיאה )במקרה של ‪ os.remove‬שגיאה‬
‫יכולה להיות שהקובץ לא קיים או שאסור למחוק אותו( נתעלם ממנה‪:‬‬

‫‪import os‬‬

‫‪def delete_file(path):‬‬
‫‪try:‬‬
‫)‪os.remove(path‬‬
‫‪except OSError:‬‬
‫‪pass‬‬

‫יש לציין ש‪ Python-‬מחפשת את קטע הקוד לטיפול בשגיאה לפי הסדר בו קטעי ה‪ except-‬כתובים‪ .‬דבר זה אומר שאם‬
‫קטע ‪ except‬אחד תופס סוג אחד של שגיאה‪ ,‬והוא בא לפני קטע ‪ except‬אחר‪ Python ,‬תנסה קודם להתאים את ה‪-‬‬
‫‪ Exception‬שנזרקה לסוג השגיאה הראשון‪ ,‬ורק לאחר מכן לסוג השגיאה שבא אחריו‪ ,‬וכן הלאה לכל קטעי ה‪:except-‬‬

‫‪>>> class GeneralFailure(Exception):‬‬


‫‪...‬‬ ‫‪pass‬‬
‫‪...‬‬
‫‪>>> class SpecificFailure(GeneralFailure):‬‬
‫‪...‬‬ ‫‪pass‬‬
‫‪...‬‬
‫‪>>> def raising():‬‬
‫‪...‬‬ ‫)(‪raise SpecificFailure‬‬
‫‪...‬‬
‫‪>>> try:‬‬
‫‪...‬‬ ‫)(‪raising‬‬
‫‪... except GeneralFailure:‬‬
‫‪...‬‬ ‫'‪print 'A general failure has occured‬‬
‫‪... except SpecificFailure:‬‬
‫‪...‬‬ ‫'‪print 'A specific failure has occured‬‬
‫‪...‬‬
‫‪A general failure has occured‬‬

‫בדוגמה הזו ניתן לראות ש‪ SpecificFailure-‬יורש מ‪ ,GeneralFailure-‬אך התוכנית שלנו מנסה לתפוס את השגיאות בסדר‬
‫כזה שבו היא מגיעה למסקנה שהשגיאה שנזרקה היא ‪ .GeneralFailure‬אמנם השגיאה היא גם מסוג ‪ ,GeneralFailure‬אך‬
‫ברור שלא נגיע לקטע הקוד שמטפל ב‪ SpecificException-‬בצורה כזו‪.‬‬
‫כדי לתפוס את ‪ SpecificException‬קודם‪ ,‬יש לשים את בלוק ה‪ except-‬של ‪ SpecificException‬לפני זה של‬
‫‪.GeneralException‬‬

‫עמוד ‪43‬‬
‫‪Python 2.5‬‬

‫להעביר את השגיאה הלאה‬


‫לאחר תפיסת השגיאה‪ ,‬אם קטע ה‪ except-‬גילה שאין לו דרך לטפל בשגיאה‪ ,‬הוא יכול להמשיך את הזריקה שלה‬
‫ולזרוק אותה הלאה‪ ,‬למישהו גבוה יותר )מישהו שהפעיל את קטע הקוד שלו(‪ ,‬כדי שאולי קטע ‪ except‬אחר יוכל לטפל‬
‫בשגיאה‪.‬‬

‫דבר זה נעשה ע"י כתיבת ‪ ,raise‬ללא פרמטרים‪ ,‬בתוך קטע ה‪:except-‬‬

‫‪... except SomeError:‬‬


‫‪...‬‬ ‫‪raise‬‬

‫למה זה טוב?‬
‫אמנם מנגנון ה‪ Exceptions-‬נראה קצת מסורבל בהתחלה‪ ,‬אבל ‪ Exceptions‬מאפשרים לכתוב קוד קצר בהרבה מקוד‬
‫"רגיל" שצריך לבדוק לאחר כל קריאה לפונקציה או פעולה על משתנה‪ .‬בגישה ה‪ ,Exceptions-‬אין צורך לבדוק ערך‬
‫החזרה מפונקציה‪ ,‬מפני שאם פונקציה צריכה להחזיר שגיאה‪ ,‬היא תזרוק ‪ ,Exception‬במקום להחזיר ערך אחר‪.‬‬

‫בנוסף‪ ,‬שיטת ה‪ Exceptions-‬מאפשרת להגדיר סוג חדש של שגיאה מבלי לשנות קוד קיים – כל מה שצריך זה להוסיף‬
‫עוד קטע ‪ .except‬לעומת זאת‪ ,‬בשיטה הישנה‪ ,‬היינו צריכים להוסיף עוד בדיקה לכל קריאה לפונקציה שיכולה להחזיר‬
‫את השגיאה החדשה‪.‬‬

‫למה זה רע?‬
‫למרות כל היתרונות )שעדיין לא כולם ברורים בשלב זה של הפרק( של ה‪ ,Exceptions-‬יש להם חסרון משמעותי‪ :‬כאשר‬
‫נזרק ‪ Exception‬והוא לא נתפס‪ ,‬הוא ימשיך לפעפע בניסיון למצוא בלוק ‪ except‬שיתפוס את השגיאה‪ .‬אם לא יימצא כזה‬
‫בלוק‪ ,‬התוכנית תקרוס‪ .‬לפעמים אנחנו מעונינים בקריסת התוכנית‪ ,‬ולפעמים התוכנית לא יכולה להמשיך לפעול וחייבים‬
‫לסיים אותה‪ ,‬אבל אי‪-‬תפיסת ‪ Exception‬שנזרקה תגרום לסיום "מכוער" של התוכנית – כלומר הדפסה של כל‬
‫הפונקציות שנקראו בדרך‪ ,‬עם עוד המון זבל שמשתמש רגיל לא יבין בכלל‪ .‬לכן יש לדאוג לסיום נקי של תוכנית‪ ,‬כלומר‬
‫תפיסת כל ‪ Exception‬שהוא‪ ,‬וטיפול מתאים בו‪.‬‬

‫הבעיה המרכזית בכתיבת קוד שמשתמש במנגנון ה‪ Exceptions-‬היא ווידוא שהקוד בטוח – תופס את כל ה‪Exceptions-‬‬
‫האפשריים‪.‬‬

‫עמוד ‪44‬‬
‫‪Python 2.5‬‬

‫פרק ‪_:12‬תרגילים‬
‫פרק זה כולל תרגילים מסכמים לחוברת זו‪.‬‬
‫מעצם היותם מסכמים‪ ,‬התרגילים לא קצרים – כלומר לוקח לא מעט זמן לכתוב אותם בפעם הראשונה‪ ,‬ובטח עם שפה‬
‫חדשה‪ ,‬ובעיקר בהתחשב בעובדה שההכרה עם השפה היא לא עמוקה ודרושה קריאה נוספת בתיעוד ומעבר נוסף על‬
‫החומר‪.‬‬
‫בנוסף‪ ,‬בגלל שמטרת התרגילים היא לתרגל את שפת ‪ ,Python‬ולא עיצוב תוכנה‪ ,‬לכל תרגיל יש המלצות בסופו לגבי‬
‫דרך המימוש המומלצת‪ .‬כמובן שאין חובה לפתור את התרגילים לפי הדרך המומלצת‪.‬‬
‫ולסיום – תשקיעו! גם אם הכל נראה ברור‪ ,‬לנסות לפתור תרגיל אחד לא יזיק‪...‬‬

‫סתם תרגיל‬
‫בתרגיל זה עליכם לכתוב תוכנית )בכל צורה שרק בא לכם( שתקבל שם קובץ‪ ,‬תפתח את הקובץ ותוסיף בתחילת כל‬
‫שורה את השם שלכם ובסוף כל שורה את שם המשפחה שלכם‪ .‬בסיום התוכנית עליכם לשמור את הקובץ המעודכן‬
‫בקובץ חדש‪.‬‬

‫המלצות‪:‬‬
‫בצעו ‪ dir‬על אובייקט הקובץ הפתוח כדי לראות מה הוא מציע‪.‬‬ ‫•‬
‫קראו בתיעוד על הפונקציה ‪ readlines‬של אובייקט קובץ‪.‬‬ ‫•‬

‫כספומט‬
‫עליכם לכתוב תוכנית שתדמה מכשיר כספומט )‪ ATM‬באנגלית(‪ .‬התוכנית תקרא‪ ,‬בעת העליה שלה‪ ,‬קובץ המכיל את‬
‫כל לקוחות הבנק‪ ,‬את מספרי החשבונות שלהם‪ ,‬את סיסמת הגישה לכספומט שלהם ואת היתרה בחשבונות שלהם‪.‬‬
‫יתרה יכולה להיות שלילית‪.‬‬
‫את מבנה הקובץ בו יישמרו הלקוחות אתם קובעים‪ ,‬ועליכם ליצור קובץ כזה בעצמכם לפני הפעלת התוכנית‪.‬‬
‫התפריט של לקוח בבנק יכיל את האפשרויות הבאות‪:‬‬
‫‪ .1‬בירור יתרה‬
‫‪ .2‬משיכת מזומנים‬
‫‪ .3‬הפקדת מזומנים‬
‫‪ .4‬שינוי סיסמא‬
‫בסיום הרצת הכספומט )ע"י הזנת חשבון מספר ‪ ,(-1‬יישמר קובץ הלקוחות‪ ,‬כאשר הוא מכיל את המצב המעודכן של‬
‫היתרות והסיסמאות של כל הלקוחות‪.‬‬

‫המלצות‪:‬‬
‫ליצור קובץ לקוחות כטקסט פשוט‪ ,‬כאשר כל שורה מייצגת לקוח‪ .‬בכל שורה יופיעו שם הלקוח‪ ,‬מספר‬ ‫•‬
‫החשבון שלו‪ ,‬הסיסמא והיתרה שלו‪ .‬כ"א מהנתונים יופרדו ברווחים או בפסיקים‪.‬‬
‫אחסון הלקוחות במילון‪ ,‬כאשר המפתח הוא מספר החשבון‪ ,‬וכל איבר הוא רשימה בת שלושה איברים‬ ‫•‬
‫המכילה את שם הלקוח‪ ,‬הסיסמא והיתרה שלו‪.‬‬
‫כאשר משתמש מקיש מספר חשבון‪ ,‬ניתן לדעת מיד האם החשבון קיים ע"י שימוש בפונקציה ‪ has_key‬של‬ ‫•‬
‫המילון‪.‬‬

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

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

‫המלצות‪:‬‬
‫עיינו במודול ‪ time‬ובפונקציות שלו‪.‬‬ ‫•‬
‫אחסון האירועים השונים ייעשה ברשימה‪ ,‬כאשר כל איבר שלה הוא מחלקה שבה שדות לאחסון כל המידע‬ ‫•‬
‫על אירוע‪.‬‬

‫מחשבון ממש משוכלל‬


‫תוכנית אחרונה תהיה מחשבון‪ ,‬כאשר מחשבון זה הוא מאוד משוכלל ומכיל קצת יותר ממחשבון כיס רגיל‪.‬‬
‫תוכנית המחשבון תהיה דומה מאוד ל‪ Interpreter-‬של ‪ – Python‬כל שעליה לעשות הוא לקלוט ביטויים מהמשתמש‬
‫ולחשב את התוצאה שלהם‪.‬‬
‫עמוד ‪45‬‬
‫‪Python 2.5‬‬

‫הפעולות שיכללו במחשבון הן‪:‬‬


‫מינימום‬ ‫מקסימום‬ ‫ממוצע‬ ‫עצרת‬ ‫מודולו‬ ‫שלילה‬ ‫חזקה‬ ‫חילוק‬ ‫כפל‬ ‫חיסור‬ ‫חיבור‬ ‫פעולה‬
‫&‬ ‫‪$‬‬ ‫@‬ ‫!‬ ‫‪%‬‬ ‫~‬ ‫^‬ ‫‪/‬‬ ‫*‬ ‫‪-‬‬ ‫‪+‬‬ ‫סימן‬
‫‪5‬‬ ‫‪5‬‬ ‫‪5‬‬ ‫‪4‬‬ ‫‪4‬‬ ‫‪6‬‬ ‫‪3‬‬ ‫‪2‬‬ ‫‪2‬‬ ‫‪1‬‬ ‫‪1‬‬ ‫עוצמה‬

‫בטבלה הזו‪ ,‬העוצמה קובעת אילו פעולות חזקות יותר מאחרות – למשל‪ ,‬חיבור חזק יותר מכפל )כי כפל בא לפני‬
‫חיבור(‪ ,‬ושלילה באה לפני כולם‪.‬‬
‫פעולות הממוצע‪ ,‬מינימום ומקסימום מקבלות שני אופרנדים‪ ,‬ומבצעות עליהם את הממוצע‪ ,‬מקסימום ומינימום‬
‫בהתאמה‪ .‬למשל‪:‬‬
‫‪ 2 @ 4‬צריך להחזיר ‪ ,3‬כי זהו הממוצע בין ‪ 2‬ל‪.4-‬‬ ‫•‬
‫‪ 7 $ 2‬צריך להחזיר ‪ ,7‬כי ‪ 7‬גבוה מ‪.2-‬‬ ‫•‬

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

‫המלצות‪:‬‬
‫לפני פענוח המחרוזת‪ ,‬להסיר את כל הרווחים שהמשתמש הוסיף – אין להם משמעות בביטוי‪.‬‬ ‫•‬
‫פענוח המחרוזת ייעשה בצורה הדרגתית‪ ,‬כאשר בכל פעם סורקים את המחרוזת מחדש כדי לחפש את‬ ‫•‬
‫הפעולה החזקה ביותר‪ .‬כאשר מוצאים פעולה חזקה‪ ,‬מבצעים אותה‪ .‬אם אין את הפעולה החזקה ביותר‪ ,‬מנסים‬
‫למצוא פעולה חלשה יותר‪.‬‬
‫בכל מעבר על הביטוי‪ ,‬פותרים את הפעולות החזקות ביותר‪ ,‬ויוצרים ביטוי חדש פשוט יותר‪ .‬את הביטוי הזה‬ ‫•‬
‫שולחים שוב לפתרון )רקורסיה(‪.‬‬
‫כאשר אין יותר פעולות לבצע‪ ,‬סימן שהביטוי פתור‪.‬‬ ‫•‬

‫עמוד ‪46‬‬

You might also like