זהו המשך לפרקי ה-Decoratorים.
פרקים קודמים:
מה נלמד
- Data classes
- Enum
- Flag
Data class
יצא לנו לא מעט לכתוב מחלקות שכל המטרה שלהן לאגד כמה פיסות מידע - אלו נקראים לרוב “מודלים” או “מחלקות מודל”.
למשל:
1 | class Person: |
עקרון תכנות שפות עיליות:
שפות עיליות מוגדרות כעיליות בגלל העזרים הרבים שהן מקנות למתכנתים.
אחד העקרונות של שפות עיליות זה להקל לנו על כתיבת הקוד.
מאחורי הקלעים השפה מייצרת לנו קוד שהיינו צריכים לכתוב לבד אילולא היא לא הייתה מייצרת את הקוד הזה.
בנאים זה משהו שחוזר על עצמו - פונקציה שמקבלת פרמטרים ומעבירה אותם לבפנים.
כל דבר שחוזר על עצמו ניתן לאגד ליחידה לוגית.
לכן dataclass
נוצר!
מה זה
1 | from dataclasses import dataclass |
dataclass
זה קישוט למחלקות שמקנה לו יכולות נוספות כמו:
- בנאי
- השוואות (אופרטורים כגון ==, !=, >, < וכדו’)
- המרה למחרוזת
כל זה עם שורת קוד אחת! מדהים.
שמתם לב שניתן לשים קישוטים גם למחלקות?
זהו אחד החוזקות של דקורטורים!
הצעה PEP-557
ההצעה הזו מסבירה יותר לעומק מה קורה מאחורי הקלעים:
בפועל השורה הקטנה הזו:@dataclass
יוצרת את המתודות הבאות מאחורי הקלעים:
- _init_ - בנאי
- _repr_ - המרה למחרוזת
- _eq_ - שווה
- _ne_ - לא שווה
- _lt_ - קטן מ
- _le_ - קטן שווה ל
- _gt_ - גדול מ
- _ge_ - גדול שווה ל
תרגיל
- כתבו מחלקות
dataclass
ל:
- אדם
- מוצר חשמלי
- רהיט
- צורה
- לקוח
חשבו על 3 תכונות (מאפיינים) לכל אחד מהמודלים הללו.
- יצרו את היררכיית מחלקות המודלים הבאה:
- חיה
- כלב
- האסקי
- כלב שועלי
1 | from dataclasses import dataclass |
1 | from dataclasses import dataclass |
Enum
Enum
הוא ערך מספרי עם שם טקסטואלי כלשהו.
ובאופן כללי יותר - זו דרך שלנו לייצג טקסט כמספר והפוך.
דוגמא א:
סוג שגיאה לקוד מספרי:
1 | שגיאת המרה - 1 |
דוגמא ב:
צבע למספר:
1 | כחול - 1 |
בפייתון
1 | from enum import Enum |
משתמשים במודול enum
.
יורשים את מחלקת Enum
(שימו לב לאותיות גדולות).
יוצרים כמשתנים במחלקה את הערכים.
תרגיל
- ממשו את הדוגמא לקוד שגיאה כ-
enum
בפייתון.
1 | from enum import Enum |
יצירה
כדי להשתמש ב-enum
שיצרנו ניתן לקרוא לו ישירות בשמו:
1 | color = Color.RED |
או להמיר מספר לערך שלו:
1 | color = Color(1) |
לקרוא את הערכים
עבור כל ערך שיצרנו ב-enum
ניתן לקרוא אותו כרשימה:
1 | for color in Color: |
תוצאה:
1 | Color.RED |
שם טקסטואלי וערכו
כמו שציינו ה-enum
משלב גם ערך מספרי וגם טקסט - השם של הערך.
ניתן לגשת לערך המספרי ע”פ השם של הערך:
1 | redColor = Color['RED'] |
כמו כן לכל ערך יש שני משתנים שניתן לקרוא מהם:
name
value
1 | redColor = Color['RED'] |
תוצאה:
1 | RED |
בעיית הייחודיות
מה מונע מאיתנו להוסיף צבע עם ערך נוסף?
1 | from enum import Enum |
נניח שבפיתוח נעשתה טעות בגלל העתק-הדבק, לעיתים זה קורה לא מעט,
ולכן גם PURPLE
קיבל את המספר 3
.
מה ייקרה פה?
1 | purple = Color(3) |
יודפס
1 | Color.BLUE |
unique
בשביל לפתור את הבעיה הזו ניתן להשתמש בדקורטור @unique
.
1 | from enum import Enum, unique |
מהות הדקורטור הוא להוסיף או לשנות התנהגות מבלי לפגוע בהתנהגות קיימת.
בעזרת unique
ניתן לפתור את הבעיה הזו.
מה קורה ב-vs code
כאשר אני מריץ את הקוד:
auto
ניתן לומר לקוד לייצר לנו את הערכים לבד בעזרת auto
וכך למנוע השמה שגויה.
1 | from enum import Enum, auto, unique |
מדפיס:
1 | 4 |
דגלים וערכים מורכבים
Flag
הוא מושג המגדיר “דגל” אשר אומר אם משהו “דלוק” או “לא דלוק”.
ממש כמו משתנה בוליאני!
אך הערך שלו הוא מספרי ולא True
או False
.
מה שFlag
משתמש בו נקרא ביט.
ביט הוא הערך הקטן ביותר בתוכנה והוא מגדיר שני ערכים בלבד - 0 או 1.
דלוק או לא דלוק.
בוליאנים ומספרים - מאחורי הקלעים
לרענון הידע על בינארי מוזמנים לחזור לפרק 12:
פייתון 12 - קבצים בינארייםביט הוא הערך הקטן ביותר - מייצג 0 או 1.בייט
מורכב מ-8 ביטים.
המחשב לא יודע להקצות רק ביט אחד - הוא יודע לעבוד עם בייטים.
למען האמת רוב מערכות ההפעלה אפילו לא עובדות עם בייטים הם עובדים עם משהו שנקרא Page
.
במערכות שונות הערך הזה יכול להיות שונה, אבל ברוב מחשבי ווינדוס הכמות זיכרון הכי קטנה שהמערכת נותנת היא 4 KiloBytes.
ז”א 4,096 בייטים או 32,768 ביטים.
המערכת נותנת את הכמות זיכרון הזו לתוכנה שלנו - קוד הפייתון,
והקוד יודע להקצות משתנים קטנים יותר.
ההבדל בין בוליאני למספר
בגלל שאין לנו יכולת לנהל ביט בודד אזי הקוד מקצה לנו בייט למשתנה שכל המטרה שלו זה 0 או 1.
יש לנו מקרים שבהם לשלם על כמות גדולה של מידע זה פשוט לא אפשרי.
למשל בפרוטוקולי תקשורת שאנחנו רוצים לצמצם את כמות המידע שלנו ככל שניתן.
או בבקרים (מחשבים קטנים) שיש לנו 64 כניסות או פחות.
אזי מספרים הם מאוד נוחים לניצול עבור דגלים.
ניתן לתאר את זה כך:
בבייט אחד יש 8 דגלים.
זו לא רשימה לכן אני לא מתחיל מ-0.
אם נדליק את הדגל הראשון:
אפשר להדליק 4 דגלים בו זמנית:
כל דגל כזה מייצג לנו ביט - דלוק או לא דלוק.
כל דגל שדלוק יהיה 1 וכל דגל שכבוי יהיה 0:
נקבל את המספר הבינארי: 00001111
.
נשים את המספר הזה במחשבון ונראה איזה מספר דצימלי נקבל:
אז כמות הדגלים הזו הביאה לנו את המספר 15.
למספר הזה אין באמת ערך עבורנו אבל ממנו אנחנו יכולים לדעת איזה דגלים דלוקים.
חשוב לדעת מהו הערך של כל ביט במספר דצימלי לפי מיקום הביט במספר, זה די פשוט:
במקום ה-1 לביט יש את הערך 1.
במקום ה-2 לביט יש את הערך 2.
במקום ה-3 לביט יש את הערך 4.
במקום ה-4 לביט יש את הערך 8.
מהו הערך בביט ה-5?
16!
כפי שאתם רואים אלו כפולות של שניים מכיוון שמתמשים בבסיס בינארי - 2!
המחשב אוהב כפולות של 2.
לכן זה ימשיך ככה…
1, 2, 4, 8, 16, 32, 64, 128, 256 וכדו’…
בפייתון
פייתון הקלה לנו על השימוש בדגלים - אנחנו לא צריכים לעשות פעולות מתמטיות בשביל להבין איזה דגל דלוק ואיזה לא.
יורשים ממחלקת Flag
ומשתמשים ב-auto
.
1 | from enum import auto, Flag |
האופרטור |
הוא פעולת OR
בין שני מספרים.
זוכרים OR
?
לפני שאתם מריצים את הקוד - מה יודפס בשני הערכים האלו?
יודפס
1 | 1 |
למה?
HasNitro - 1
HasSideWings - 2
HasGun - 4
HasArmor - 8
הערך של - Warrior
משולב מ - 1, 2, 41+2+4 = 7
.
_contains_
על מנת לבדוק אם דגל דלוק ניתן להשתמש ב-__contains__
.
1 | options = CarOptions.Warrior |
תרגיל
1.
כתבו Enum
המייצג את השלב שבו חבילת דואר נמצאת.
תחשבו על איזה מצבים החבילת דואר תהיה בהן.
- בסעיף הזה אשלב משהו מעט יותר מורכב - דגלי TCP.
ניתן לקרוא עליהם כאן
לא חייב להבין מה הם עושים - אך נסו לממש מחלקה שמכילה את כל הדגלים.
1 | from enum import Enum, auto |
1 | from enum import Flag, auto |
בפרק הבא נלמד לעומק יותר על Iteratable
ו-Generators
: