
global. בלי המילה מתקבלת שגיאה "referenced before assignment", כי פייתון מתייחסת למשתנה כמקומי.nonlocal, שמאפשרת לשנות משתנה של הפונקציה החיצונית. בפייתון 2.7 הדבר אינו נתמך.@ מעל הפונקציה המקורית. בדוגמה דקורטור מודד את זמן הריצה ומדפיס אותו, בלי לשנות את הפונקציה המקורית.lru_cache, שמחזיר תוצאה שמורה כשהפונקציה נקראת שוב עם אותם ארגומנטים.global מוביל לשגיאה או ליצירת משתנה מקומי חדש.הטקסט המלא של הדקות הראשונות בהרצאה «פונקציות בפייטון - חלק 2» בקורס הווידאו של PracticU – כתוביות בעברית עם זמן התחלה לכל פסקה. כך תוכלו לקרוא ולחפש את הנושאים לפני שמתחילים ללמוד.
שלום לכולם, בשיעור הזה אנחנו נדבר על חומר מתקדם של פונקציות ברמה של סקופים, ברמה של פונקציות קוראות לפונקציות, פונקציות בתוך פונקציות, אז בואו נתחיל.
נתחיל בלהגדיר משתנה שנקרא, הייתי רוצה לעשות את החלק הזה דבר ראשון באינטראקטיב מורד, זה נראה לי יהיה יותר קל, נפתח פה רגע של, אוקיי, אז בואו נגדיר משתנה x שווה, להעביר פונקציה שמקראת x שמקבלת איזשהו...
שהיא לא מקבלת כלום, והיא מדפיסה פעם איזשהו סטרינג לידה שנכנסת אליה. בואו נראה שהפונקציה הזאת עובדת. כן, הפונקציה עובדת.
עכשיו, מה יקרה אם אני אצור פה משתנה שנקרא x ואשים בו את הערך 5? האם אני יכול עדיין לקרוא לפונקציה? אז דבר ראשון x קיים, וניסיון לקרוא ל-x 5 יביא לי exception.
כלומר, סקופים פונקציות מזוהות רק על ידי השם כלומר לא יכול להיות לי משתנה ופונקציה עם אותו שם לפחות לא באותו קובץ או באותו זמן בעצם אפשר להסתכל על זה שכל פעם שאני קורא לאיזשהו אובייקט או מנסה למצוא איזשהו אובייקט בסקופ שלי יש איזשהו דיקשנרי שפייתון מחפש שם ואז כשהוא מחפש שם הוא מנסה לעשות את הפעולה
שאותה ניסינו לעשות למשל אני מחפש פה אובייקט שנקרא x ואני מנסה לקרוא לו כלומר, אני חושב שהאובייקט הזה הוא אובייקט שהוא callable, שאפשר לקרוא לו.
פייתון מוצא את האובייקט x, אבל הוא מגלה שלאובייקט הזה אי אפשר לקרוא, ולכן הוא זורק לי exception. אז זה משהו חשוב שלדעת על שמות של פונקציות ועל סקורפים.
שימו לב מה ה-exception אומר: int object is not callable. בעצם אין לנו x שווה למספר, ומספר הוא לא פונקציה. אי אפשר לקרוא למספר בתור פונקציה, כי מספר הוא מספר ופונקציה זה פונקציה.
כל אחד היום הוא שונה לגמרי וברור שאי אפשר לקרוא למספר כמו פונקציה. עכשיו נחזור לאקליפס ונדבר קצת על סקופים. נגיד שיש לי x שהוא שווה ל-90 ויש לי עוד פונקציה, הפעם עם שם תקין, מייפאנק.
שימו לב ששם של פונקציה חייב להתחיל בסטרינג, היא לא יכולה להתחיל בפארס, כמו השם של משתנה, זה משהו שהוא בכל השפות כמעט כאב.
בואו נעשה print x. עכשיו שימו לב שx לא מוגדר בפונקציה הוא מוגדר מעל הפונקציה האם פייתון תדע לזהות אותו התשובה היא כן רגע רק רגע אחר כך הדבר הכי חשוב להוסיף קריאה על הפונקציה כמובן בואו נראה עכשיו אז כן פייתון מזהה את x והאמת זה גם נראה הייתי לא יודע אם זה היה טריוויאלי אבל יש בזה היגיון מסוים כי אולי לא אני לא יודע בעצם
פייתון מחפשת את x היא לא מוצאת אותו היא רואה אם יש x אחר באזור והיא מוצאת אותו אומרת סבבה כנראה התכוונת לx הזה הx הזה הוא גלובלי כנראה התכוונת אליו וזה בסדר עכשיו מה יקרה אם אני אגיד אני רוצה שx יהיה שווה 10 אני רוצה גם להדפיס
אותו להדפיס את x ופה גם נעשה כזה דבר נוסיף פה הדפסה של x וגם נוסיף אחרי הקריאה לפונקציה בוא נראה מה יקרה עכשיו וגם נוסיף איזשהו שנדע שנדע מה זה מה בוא נעשה פה before בוא נעשה after בוא נעשה in ככה נדע בדיוק מה קורה איפה ולא יהיו לנו בלגולים אוקיי אז before x שווה 90 after in שווה 10 ואפטר שווה 90
כלומר, מה שקרה לנו פה זה שמצד אחד יש לנו את ה-X שקיים ב-scope הזה, ב-scope הגלובלי, ויש לנו את X שהוא נמצא בתוך הפונקציה, לא מדובר באותו X, שניהם קיימים בו זמנית, שניהם חיים זה לצד זה, ואנחנו לא יכולים מתוך הפונקציה שלנו לשנות את ה-X החיצוני, לפחות לא בדרך הזאת.
עכשיו, מה יקרה אם אני אגיד לפייתון, אל תעשה לי X חדש בתוך הפונקציה, תעשה לי X פלוס שווה 10, אולי עכשיו הוא יבין שאני מדבר על x קיים?
אז לכאורה כן, בפועל הוא לא נותן. כלומר, הוא אומר, local variable x reference before assignment. כלומר, מה הוא אומר? הוא אומר, אתה מנסה פה לעשות פלוס שווה למשהו שלא קיים בכלל, אתה לא יכול לעשות את הדבר הזה, אתה צריך קודם כל ליצור אותו.
פלוס שווה למה? מה הערך הראשון שלו? אני לא יודע, אני רק יודע שאתה עושה לו פלוס שווה. עכשיו, מה יקרה אם היינו רוצים להשתמש ב-x בתוך הפונקציה שלנו?
בשביל זה יש מילה שמורה שנקראת Global. Global x, לאחר מכן פייתון מבינה, אוקיי, בפונקציה הזאת עומד להיות שימוש במשתנה גלובלי בשם x, עכשיו אתה יכול לעשות לו פלוס שווה, ועכשיו בעצם נקבל את התוצאה שאולי רצינו, אולי לא, תלוי כל, תלוי כמובן במה שהתכוונו לעשות,
אבל קיבלנו את התוצאה הזאת, שאנחנו, יש לנו רק x אחד בתוכנית, והפונקציה מתייחסת לx שנמצא פה למעלה. שימו לב, דבר חשוב, בואו רגע נחזיר את הגלובל, בואו נעשה x שווה 20. מה יקרה פה?
בואו נריץ. before x שווה 90, כי x מוגדר פה בתור 90. בתוך הפונקציה הוא מוגדר 10, אבל אחרי הוא מוגדר 20. עכשיו, בואו נעשה את זה מעניין ונוסיף global x ונעשה פלוס שווה.
מה יהיה x שווה עכשיו? x שווה 30. מה שקורה, פייתון עובדת בצורה של דיקשנרי. כלומר, כל סקופ הוא ברמת הדיקשנרי. אייטון מתחילה לקרוא את הכובד הזה, והיא אומרת, אוקיי, יש לי פה ערך שנקרא x, אני מוסיפה אותו לדיקשנרי של התוכנית שלי, ואני שמה, בואו סתם נכתוב את זה פה, אני שמה בערך x מספר 90. ואז היא ממשיכה לפרסר את הכובד,
והיא רואה שיש פונקציה שנקראת myfunk, אז היא כותבת לעצמה, אוקיי, אז יש לי איזושהי פונקציה שנקראת myfunk, והערך שלה מצביע על איזשהו function object, לא באמת, כמובן שזה לא...
נגיד שזה דיקשנרי רק בשביל הפשטות של העניין. עכשיו פייתון ממשיכה, היא רואה שיש פה איזשהו פרינט, היא רואה שיש פה עוד x ששווה 20. היא לא יכולה לשים את ה-x הזה פה בדיקשנרי כי x כבר קיים ובדיקשנרי חייב להיות חד ערכי, כלומר לא יכול להיות קי כפול בדיקשנרי.
כל הקטע בדיקשנרי זה שכל קי מופיע רק פעם אחת, אז היא הולכת לקי הזה והיא מוחקת אותו, כלומר היא לא מוחקת אותו, מרחיקת את הערך שלו, והיא שמה שם 20.
ואז כשמיי פאנק מתחילה לרוץ, היא אומרת, אוקיי, יש לנו גלובל איקס. הגלובל איקס הזה, איפה הוא? הוא נמצא בדיקשנרי הגלובלי שלי, שזה הגלובל דיקשנרי שלי, בוא נקרא לו g, ואז היא רואה שx שווה 20, ואז היא מוסיפה לו עוד 10, זה נהיה 30, ואז היא יוצאת החוצה ומדפיסה.
עכשיו שימו לב שגם לכל פונקציה יש דיקשנרי פנימי, למשל בדיקשנרי של לוקאל, אם היינו רוצים שנים אותו להיות ככה, אז מופיע לנו בסך הכל x שמצביע לערך 10, ואז אם היינו עושים x פלוס שווה, בלי גלובל, מה שקורה, פייתון מחפשת את myfunk בתוך לוקאל, היא לא מוצאת אותו, ואז היא יוצאת החוצה,
אם היא לא מוצאת אותו, ואז יש אקספצ'ן, כי אין גלובל, אז היא לא מנסה לחפש אותו למעלה. בואו רק לסיום, בואו נראה לכם גם שזה עובד. נמחק את x מלמעלה ונעיף גם את ההתפסה הזאת, כי פה בעצם x עוד לא קיים.
פה בעצם אפשר להזיז אותה לפה, זה לא משנה. ונוסיף גם גלובל כמובן, ועכשיו הכל יעבוד, למרות שx מוגדר אחרי, כי בעצם פיינטון תוך כדי ריצה היא רואה מה יש.
כלומר, אם אני עכשיו אעשה פה עוד פעם x שווה 50, הפונקציה עכשיו מתייחסת ל-x חדש. אותה פונקציה, אותו קוד, מוצא x במקום אחר היא לא זוכרת מה היה x הקודם כי היא מסתכלת בגלובל דיקשנרי כלומר בסקורפ הגלובלי ורואה מה רשום שם ועכשיו יש שם x שווה
50. אני יכול גם לכתוב שיהיה פה 100 ויכול לעשות את זה עוד כמה פעמים בסופו של דבר הערך נקבע דינמית לא בזמן קומפילציה אלא בזמן ריצה בזמן ריצה הפייתון בודק איפה x נמצא מה הערך שלו ולפי זה הוא מדפיס אותו.
בואו נדבר קצת על פונקציות בתוך פונקציות אוקיי בואו נגיד שאנחנו רוצים פונקציה שאותה פונקציה ביי פאנק שהיא מקבלת איזשהו פאראם והיא מקבלת גם מספרים num1 ו-num2 והפונקציה עושה כזה דבר if פאראם מגדירה פונקציה פנימית נקרא לה add והיא מחזירה num ועוד num2 אחרת היא
דירה פונקציה שנקראת מולטי, והפונקציה הזאת נעשה שלא, בוא נעשה ששניהם גם מחזירות וגם שפול בוא נעשה שגם מחזירות את זה וגם מדפיסות את זה שיהיה יותר נחמד עכשיו נקרא לפונקציה שלנו עם איזשהו true ושתיים ושלוש ובוא נראה מה קורה הלו מיי פאנק ואה ושכחתי כמובן להוסיף את הקריאה לפונקציה אוקיי קיבלנו ארבע
עכשיו אם גם נעשה ככה, עכשיו, כל זה האמת חוץ מהקטע שהגדרתי פה פונקציה בתוך if statement שזה אולי קצת ירים גבה, לא, לא נראה לי שהראתי פה משהו ממש מטורף.
אבל בוא, בוא ננסה קצת לסבך את העניינים. מה יקרה אם אני עושה כזה דבר? יש לנו פה בקוד אחד שתי פונקציות עם אותו שם. האם הוא יודע למה לקרוא?
וואי, כן. כלומר, פייתרום לזמן ריצה הבינה, הכנסה פה ל-if, היא ראתה אם הוא true או false, אם הוא true היא יצרה את הפונקציה הזאת, אם הוא false היא יצרה את הפונקציה הזאת, את האובייקט הזה, כלומר בתוך הפונקציה הזאת יש לי עוד פעם dictionary שמכיל בתוכו param שהערך שלו הוא true או false, זה לא משנה, תלוי בקריאה, ויש לי את num1 ו-num2 ובזמן ריצה היא גם מוסיפה לפה את האד שהוא מצביע
לאד הנכון, כלומר, או ל-ad אחד, או ל-ad שתיים, ובסוף, אחרי שהיא יצרה את ה-ad הזה, היא קוראת לו. שימו לב שגם אם הייתי עושה כזה דבר, זה גם