פרק קודם:
פייתון 20 - פונקציות קישוט חלק אבספריות פייתון קיימים שימושים שונים ל-Decorators
.
נבין כמה מהשימושים הנפוצים.
מה שאנחנו רוצים להשיג זה להעביר פרמטר ל-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
.
אחת הבעיות שיש לנו עם Decoratorים זה שהם מאבדים את המידע על הפונקציה המקורית.
למשל אם אני לא אשים את ה-wraps
:
1 | import functools |
במקרה הזה מה שיודפס בסוף זה:
1 | Funk Funk and only Funk |
ועם השורה הזו:
1 |
|
מודפסת שם הפונקציה המקורית:
1 | Funk Funk and only Funk |
ממשו את ה-Decorator הבא:
1 |
|
הוא ייקרא לפונקציה כמספר הפעמים שהמשתמש הביא לו בפרמטר Times
.
1 | import functools |
מחלקה אבסטרקטית היא מחלקה שלא ניתן ליצור משתנה חדש שלה.
בפסודו קוד שדומה לפייתון נכתוב:
1 | abstract class A: |
בדוגמא הזו מחלקה A
אבסטרקטית ולכן לא ניתן ליצור ממנה מופיע חדש,
לעומת מחלקה B
שניתן כי היא יורשת את - A
.
איך נעשה זאת בפייתון?abc
בא להציל אותנו!
המודול abc
נותן לנו בעזרת פונקציות קישוט את היכולת לעשות פונקציה אבסטרקטית.
אני רואה בזה אחד החסרונות הגדולים של פייתון שהשפה עצמה לא מממשת את מודל הירושה הקלאסי ונותן לנו ליצור מחלקות אבסטרקטיות.
מחלקות אבסטרקטיות מקנות לנו את היכולת להגדיר ממשקים באופן קל יותר,
כמו כן דרך הקוד לומר לשאר המתכנתים שמשתמשים בקוד
“לא ניתן ולא צריך ליצור מופע מהמחלקה הזו”
אחת הדרכים לתקשר את ה-API שאנחנו כותבים היא דרך הגבלות.
כדי לסמן מחלקה כאבסטרקטית צריך לרשת מ-ABC
:
*שימו לב לאותיות גדולות וקטנות - המודול נקרא abc
והמחלקה האבסטרקטית היא ABC
.
1 | import abc |
עדיין זה מאפשר ליצור מופעים חדשים - כדי שהיא תהיה אבסטרקטית צריך להגדיר מתודות אבסטרקטיות למימוש!
ה-Decorator abstractmethod
מתייג את הפונקציה כמתודה אבסטרקטית שהמחלקה המממשת צריכה לממש גם כן!
נסו להוריד את ההערה ולהריץ את הקוד עם מופע חדש של Provider
.
1 | import abc |
מאפיין הוא סוג של פונקציה שמקצרת את היכולת לקבל ולערוך ערכים במחלקה.
בגדול מה שאנחנו רוצים לעשות עם מאפיין זה לגשת בדרך בטוחה למידה פנימי של מחלקה.
בקוד זה נראה ככה:
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!