פרק קודם:
פייתון 21 - פונקציות קישוט חלק אמה נלמד
- שימושים נפוצים בפייתון
- העברת פרמטר ל-Decorator
- functools.wraps
- ABC - Abstract Base Class
- AbstractMethod
- Property
שימושים נפוצים בפייתון
בספריות פייתון קיימים שימושים שונים ל-Decorators
.
נבין כמה מהשימושים הנפוצים.
העברת פרמטרים לפונקציות שהן בעצמן Decorator
מה שאנחנו רוצים להשיג זה להעביר פרמטר ל-Decorator.
למשל:
1 |
|
המודול functools
נותן לנו יכולות נוספות לשימוש כדי לבנות התנהגות.
כדי לפשט את חוט המחשבה - תחשבו שאנחנו בונים פאזל שכל חלק ממנו הוא פונקציה - אנחנו משנים את סדר הקריאה או מוסיפים לקריאות פרמטרים כדי להתאים את זה למה שאנחנו רוצים.
הלוגיקה הבאה מגנה על פונקציה בקריאה שלה ומאשימה את המפתח שפיתח את הפונקציה הזו!
1 | import functools |
קודם כל הדבר הראשון שצריך לשים לב זה שיש לנו פונקציה פנימית נוספת שלה בעצמה יש Decorator!
הפונקציה wrapper
מקבלת את הקישוט wraps
.wraps
מקבלת כפרמטר את הפונקציה ש-actual_decorator
מקבלת.
ז”א func
היא הפונקציה המקורית שלנו - SomeFunkyFunc
.
השורה:
1 | return wrapper |
בעצם מחזירה פונקציה אחרת, היא מחזירה את - wraps
אשר עוטפת את wrapper
.
ניתן להבין זאת בדיאגרמה הבאה:
יש לנו עטיפות רבות כדי לעשות את הלוגיקה שאנחנו רוצים ולהעביר פרמטר.
פונקציית GuardAndBlame
היא המממשת של העברת פרמטרים והיא משמשת כשכבה שנותנת לנו את הפרמטרים האלו.
1 | def GuardAndBlame(developerName=''): |
הפונקציה actual_decorator
היא הפונקציה המקורית שהיינו כותבים - היא הראשונה שמקבלת את func
כפרמטר.
1 | def actual_decorator(func): |
ה-Decorator האמיתי הוא בגוף הפונקציה וממומש בעזרת wraps
.
1 |
|
כדי להבין את זה יותר טוב ניתן לקרוא באנגלית:
wrapper wraps func
ו-wraps
כבר מממש לנו את כל הלוגיקה של ה-Decorator שאתם מכירים מהפרק הקודם.
הנה החלק הקשה יותר להבנה, הפונקציה הזו נקראת ומחזירה פונקציה שישר קוראים לה.
השורת קוד הזו:
1 |
מתורגמת ל:
1 | SomeFunkyFunc = GuardAndBlame('Bob')(SomeFunkyFunc) |
זה למה הפונקציה actual_decorator
היא בעצם הדקורטור האמיתי שמקבלת את -SomeFunkyFunc
.
למה functools.wraps?
אחת הבעיות שיש לנו עם Decoratorים זה שהם מאבדים את המידע על הפונקציה המקורית.
למשל אם אני לא אשים את ה-wraps
:
1 | import functools |
במקרה הזה מה שיודפס בסוף זה:
1 | Funk Funk and only Funk |
ועם השורה הזו:
1 |
|
מודפסת שם הפונקציה המקורית:
1 | Funk Funk and only Funk |
תרגיל
ממשו את ה-Decorator הבא:
1 |
|
הוא ייקרא לפונקציה כמספר הפעמים שהמשתמש הביא לו בפרמטר Times
.
1 | import functools |
Abstract Base Classes
מחלקה אבסטרקטית היא מחלקה שלא ניתן ליצור משתנה חדש שלה.
בפסודו קוד שדומה לפייתון נכתוב:
1 | abstract class A: |
בדוגמא הזו מחלקה A
אבסטרקטית ולכן לא ניתן ליצור ממנה מופיע חדש,
לעומת מחלקה B
שניתן כי היא יורשת את - A
.
איך נעשה זאת בפייתון?abc
בא להציל אותנו!
המודול abc
נותן לנו בעזרת פונקציות קישוט את היכולת לעשות פונקציה אבסטרקטית.
אני רואה בזה אחד החסרונות הגדולים של פייתון שהשפה עצמה לא מממשת את מודל הירושה הקלאסי ונותן לנו ליצור מחלקות אבסטרקטיות.
מחלקות אבסטרקטיות מקנות לנו את היכולת להגדיר ממשקים באופן קל יותר,
כמו כן דרך הקוד לומר לשאר המתכנתים שמשתמשים בקוד
“לא ניתן ולא צריך ליצור מופע מהמחלקה הזו”
אחת הדרכים לתקשר את ה-API שאנחנו כותבים היא דרך הגבלות.
המחלקה ABC
כדי לסמן מחלקה כאבסטרקטית צריך לרשת מ-ABC
:
*שימו לב לאותיות גדולות וקטנות - המודול נקרא abc
והמחלקה האבסטרקטית היא ABC
.
1 | import abc |
עדיין זה מאפשר ליצור מופעים חדשים - כדי שהיא תהיה אבסטרקטית צריך להגדיר מתודות אבסטרקטיות למימוש!
@abstractmethod
ה-Decorator abstractmethod
מתייג את הפונקציה כמתודה אבסטרקטית שהמחלקה המממשת צריכה לממש גם כן!
נסו להוריד את ההערה ולהריץ את הקוד עם מופע חדש של Provider
.
1 | import abc |
@property
מאפיין הוא סוג של פונקציה שמקצרת את היכולת לקבל ולערוך ערכים במחלקה.
בגדול מה שאנחנו רוצים לעשות עם מאפיין זה לגשת בדרך בטוחה למידה פנימי של מחלקה.
בקוד זה נראה ככה:
1 | a.X = 2 |
דרך ראשונה לממש מאפיין
לשים ערך ציבורי מהמחלקה
1 | class A: |
דרך שנייה לממש מאפיין
פונקציות getXXX
ו-setXXX
.
1 | class A: |
דרך שלישית לממש מאפיין
שימוש ב-@property
1 | from abc import ABC |
היתרון בלהשתמש ב-Decorator הזה הוא שיש לנו גם את התחביר שניתן להשתמש ב-X
ישירות וגם הגדרה של פונקציות.
ככה שניתן לכתוב קוד נוסף כשאנחנו רוצים:
1 | from abc import ABC |
תרגיל
1.
בבלנדר יש סכין שניתנת להחלפה.
ממשו תכנית קטנה שמאפשרת למחלקת בלנדר להחליף את הסכין שהבלנדר חותך בעזרתו.
על מחלקת הסכין גם להגדיר מאפיין abstract Get-Only property שמחזיר במספר מ1-10 כמה חדה הסכין.
- כתבו מחלקה אבסטרקטית ל”צורה”.
למחלקה תהיה מתודה לחישוב השטח.
ממשו מחלקות נוספות המממשות את “צורה”:
- ריבוע
- מלבן
- עיגול
- משולש
1 | from abc import ABC,abstractmethod |
1 | from abc import ABC,abstractmethod |
השימושים שלנו ב-Decoratorים עוד לא הסתיימו.
בפרק הבא נראה שני פיצ’רים שהופכים את החיים להרבה יותר נוחים.
DataClass & Enum!