MICROSOFT LOGO
MICROSOFT LOGO
קורס Python

קורס Python – המדריך המלא

פייתון היא שפת תכנות עילית ועוצמתית, הידועה בפשטות ובקריאות שלה. היא מאמצת תחביר ברור ומובע שלרוב נראה כמו קוד דמוי פסאודו, תוך הדגשת הפילוסופיה ש"קריאות חשובה." פילוסופיית עיצוב זו מובעת ב-"Zen of Python" (ניתן לגשת אליו על ידי הפקודה import this), שמדגיש עקרונות מנחים כגון "יפה עדיף על מכוער" ו"גלוי עדיף על סמוי."
carmel website
carmel-website
carmel-website

פייתון (Python) מתקדם

פייתון היא שפת תכנות עילית ועוצמתית, הידועה בפשטות ובקריאות שלה. היא מאמצת תחביר ברור ומובע שלרוב נראה כמו קוד דמוי פסאודו, תוך הדגשת הפילוסופיה ש"קריאות חשובה." פילוסופיית עיצוב זו מובעת ב-"Zen of Python" (ניתן לגשת אליו על ידי הפקודה import this), שמדגיש עקרונות מנחים כגון "יפה עדיף על מכוער" ו"גלוי עדיף על סמוי." יתרונותיה של פייתון כוללים ספריית סטנדרט נרחבת ("כולל את כל הסוללות") ואקוסיסטם עשיר של חבילות צד שלישי כמעט לכל תחום – מפיתוח אתרים ועד חישובים מדעיים. פייתון תומכת בפרדיגמות תכנות שונות (פרוצדורלית, מונחית עצמים, ופונקציונלית) ורצה על מערכות הפעלה רבות, מה שהופך אותה לבחירה רב-שימושית עבור מגוון רחב של פרויקטים.

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

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

  • צלילה לעומק הליבה של פייתון: מודל הנתונים של פייתון, פונקציות מתקדמות (דקורטורים, גנרטורים, מנהלי הקשר), והכוונת טיפוסים (type hinting).
  • מטא-תכנות: תכונות דינמיות כמו מטא-קלסיים, יצירת מחלקות דינמית, מתארים (descriptors) ובחינת קוד בזמן ריצה (introspection).
  • ריבוי תהליכים ותכנות אסינכרוני: Threading, multiprocessing, asyncio, ואיך פייתון מתמודדת עם מקביליות וריבוי משימות.
  • AI ולמידת מכונה: סט הכלים המדעי של פייתון – NumPy, Pandas, scikit-learn – ולמידה עמוקה עם TensorFlow/PyTorch, כולל בניית צינורות ML ופריסת מודלים.
  • פיתוח אתרים: מסגרות עבודה מתקדמות (Flask, Django, FastAPI), בניית ממשקי API מסוג REST ו-GraphQL, שיקולי אבטחה, ופריסת אפליקציות ווב.
  • הנדסת נתונים: בניית צינורות נתונים ותהליכי ETL, תזמון תהליכים עם Apache Airflow, זרימת נתונים (streaming), עיבוד ביג דאטה עם PySpark, ואינטגרציה עם מסדי נתונים.
  • אריזת פרויקטים, בדיקות ו-CI/CD: אריזת פרויקטים בצורה תקינה, פרסום ל-PyPI, כתיבת בדיקות עם pytest, ואוטומציה של בדיקות איכות ופריסה עם תהליכי CI/CD (למשל GitHub Actions).
  • מגמות מתקדמות: התפתחויות חדשות כגון MLOps (יישום DevOps בעולם ה-ML), מחשוב Serverless בפייתון, פייתון בקצה הרשת (IoT ותכנות משובץ), תבניות מודרניות ל-API, ובדיקות אבטחה מתקדמות.

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

צלילה לעומק הליבה של פייתון

בפרק הזה נלמד לעומק את המרכיבים הבסיסיים והחשובים ביותר של פייתון, ברמה מתקדמת. פייתון נראית פשוטה על פני השטח, אבל מאחורי הקלעים יש לה מבנה נתונים חכם ומערכת ריצה מורכבת. נבין איך אובייקטים בפייתון באמת עובדים, ואיך משתמשים בכלים מתקדמים כמו דקורטורים (decorators), גנרטורים (generators), ומנהלי הקשר (context managers). בנוסף, נעסוק גם בהכוונת טיפוסים (type hinting) – נושא שהופך ליותר ויותר חשוב בפרויקטים גדולים. הבנה טובה של הנושאים האלו תאפשר לכם לכתוב קוד פייתון מקצועי, נכון ויעיל יותר.

מודל הנתונים של פייתון הוא הבסיס למערכת האובייקטים של השפה. בפייתון, הכול הוא אובייקט – לא רק מבני נתונים,אלא גם פונקציות, מחלקות, ואפילו מודולים נחשבים כאובייקטים. כמו שכתוב בתיעוד הרשמי:
“כל המידע בתוכנית פייתון מיוצג על ידי אובייקטים או על ידי קשרים בין אובייקטים.”

אובייקטים

לכל אובייקט בפייתון יש שלוש תכונות עיקריות:

  • זהות (Identity): מזהה ייחודי של האובייקט (ב-CPython זה בדרך כלל כתובת הזיכרון, וניתן לגשת אליה עם הפונקציה id()). האופרטור is משמש להשוואת זהות בין אובייקטים.
  • טיפוס (Type): סוג האובייקט (כלומר המחלקה שלו), שקובע אילו פעולות ניתן לבצע עליו. גם הטיפוס עצמו הוא אובייקט (מהסוג type או תת-מחלקה שלו), והוא לא ניתן לשינוי. ניתן לבדוק את סוג האובייקט בעזרת הפונקציה type().
  • ערך (Value): המידע או המצב הפנימי שהאובייקט מכיל. ישנם אובייקטים שהערך הפנימי שלהם יכול להשתנות (כמו רשימות ומילונים – mutable), ויש כאלה שלא ניתן לשנות לאחר יצירתם (כמו טאפלים, מחרוזות ומספרים – immutable).

הבנה של ההבדל בין אובייקטים ניתנים לשינוי (mutable) ואובייקטים שאינם ניתנים לשינוי (immutable) היא חשובה מאוד.

אובייקטים שאינם ניתנים לשינוי, כמו טאפלים או מחרוזות, לא ניתן לשנות לאחר יצירתם – כל פעולה שנראית כאילו היא משנה אותם בפועל יוצרת אובייקט חדש.
לעומת זאת, אובייקטים ניתנים לשינוי, כמו רשימות או מילונים, אפשר לשנות "במקום" – כלומר, ללא יצירה של אובייקט חדש.

ההבדל הזה חשוב לכתיבת קוד בטוח – למשל, שימוש בפרמטרים ברירת מחדל שהם אובייקטים ניתנים לשינוי בפונקציות עלול לגרום לבאגים שקשה לאתר.
זה גם משפיע על אופן ההעתקה של אובייקטים (העתקה שטחית לעומת העתקה עמוקה), ועל ההתנהגות שלהם כמפתחות במילונים או כפריטים בקבוצות – רק אובייקטים שאינם ניתנים לשינוי ניתנים לגיבוב (hashable) כברירת מחדל.

מתודות

מודל הנתונים של פייתון מגדיר מערך עשיר של מתודות מיוחדות (שנקראות לעיתים “dunder” – קיצור של double underscore, כמו __add__, __len__, __repr__), שמאפשרות למחלקות שאתם מגדירים להתנהג כמו טיפוסים מובנים בשפה.
באמצעות מימוש המתודות הללו, האובייקטים שלכם יכולים לתמוך בפעולות ובפרוטוקולים הבנויים של פייתון:

  • הדמיית טיפוסים מספריים: מימוש מתודות כמו __add__, __sub__ וכו' מאפשר לקבוע כיצד יתבצעו פעולות חשבוניות על האובייקט.
  • הדמיית מבני נתונים/רצפים: מימוש פרוטוקולים של מיכלים כמו __len__ (תמיכה ב-len()), __getitem__ (גישה לפי אינדקס ואיטרציה), __setitem__, __iter__, ו-__next__ כדי לתמוך באיטרציה.
  • הצגת מחרוזות: __repr__ קובעת את המייצג הרשמי של האובייקט (שימושי לניפוי שגיאות), ו-__str__ משמשת להצגה ידידותית למשתמש.
  • בקרה על גישה לשדות: __getattr__ ו-__setattr__ מאפשרות שליטה בהתנהגות כאשר ניגשים לשדה או מגדירים אותו. __getattribute__ היא מתודה מתקדמת יותר שנקראת תמיד בגישה לשדה, ודורשת זהירות בשימוש.

לדוגמה, אם תממשו את __iter__ ו-__next__ במחלקה – תוכלו להפוך את האובייקט שלכם לאיטרבילי (ולכן להשתמש בו בלולאת for). אם תממשו את __enter__ ו-__exit__, תוכלו להשתמש באובייקט עם הפקודה with (כמנהל הקשר – context manager, נושא שנדון בו בהמשך).

מודל הנתונים של פייתון הוא עוצמתי – הוא מאפשר לכם ליצור אובייקטים מותאמים אישית שמתנהגים כמו אובייקטים מובנים בשפה, וכך מאפשרים ביטוי טבעי של רעיונות. כך למשל, ספריות כמו Pandas או NumPy מצליחות להשתלב באופן חלק עם תחביר פייתון.

דוגמה – יצירת אובייקט איטרבילי מותאם אישית

הדוגמה הבאה מגדירה מיכל (container) מותאם אישית שמממש חלק מפרוטוקול הרצפים (sequence protocol), מה שמאפשר לבצע עליו איטרציה (מעבר בלולאה) ואינדוקס (גישה לפי אינדקס):

מודל הנתונים והאובייקטים של פייתון

בקוד הזה, המחלקה FibSequence מסוגלת להפיק רצף פיבונאצ’י אינסופי. היא מממשת את __iter__ ו-__next__, ולכן היא מתנהגת כאיטרטור. בנוסף, היא מממשת גם את getitem, מה שמאפשר לגשת לאיברי רצף לפי אינדקס באמצעות סוגריים מרובעים. דוגמה זו מדגימה כיצד מודל הנתונים של פייתון מאפשר לשלב אובייקטים מותאמים אישית עם תחביר מובנה של אינרציה ואינדוקס.

פונקציות כאובייקטים מהשורה הראשונה ודקורטורים

פונקציות

בפייתון, פונקציות הן אובייקטים מהשורה הראשונה (first-class objects). המשמעות היא שאפשר:

  • לשמור פונקציות במשתנים
  • להעביר פונקציות כפרמטרים לפונקציות אחרות
  • להחזיר פונקציות מתוך פונקציות
  • ואפילו להגדיר פונקציות בתוך פונקציות

היכולת הזו מאפשרת להשתמש בתבניות מתקדמות כמו פונקציות מסדר גבוה (higher-order functions) ודקורטורים.

דקורטורים

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

לדוגמה, הנה דקורטור פשוט שמדפיס הודעה לפני ואחרי קריאה לפונקציה:

פונקציות כאובייקטים מהשורה הראשונה ודקורטורים

בקטע הקוד הזה, log calls הוא דקורטור. אנחנו מחילים אותו על הפונקציה add באמצעות התחביר @log calls. הפונקציה הפנימית wrapper "עוטפת" את הפונקציה המקורית func, ומוסיפה הדפסות לפני ואחרי ההרצה שלה. בצורה זו, מבלי לשנות את הקוד של add, הוספנו לה התנהגות של רישום (logging).

דקורטורים משמשים לרוב לטיפול בדאגות רוחביות (cross-cutting concerns) כמו

  • רישום (logging)
  • בקרת גישה
  • מדידת זמן
  • שמירה במטמון (caching)
  • ניטור ומדדים (instrumentation)

נקודות חשובות על דקורטורים

  • ניתן לערום דקורטורים אחד על השני (stacking) – כלומר להחיל כמה דקורטורים על אותה פונקציה, והיא תיעטף בשכבות רבות.
  • כדי לשמר את המטא-נתונים של הפונקציה המקורית (כמו שמה או תיעוד ה-docstring שלה), יש להשתמש ב-functools.wraps בתוך ההגדרה של ה-wrapper. לדוגמה, להוסיף @functools.wraps(func) מעל הפונקציה הפנימית wrapper יעביר את המטא-נתונים מ-func אל wrapper.
  • דקורטורים יכולים גם לפעול על מחלקות – לשנות או להוסיף התנהגות להגדרה של מחלקה. לדוגמה, @dataclass הוא דקורטור שמוסיף אוטומטית מתודות למחלקה כמו init, repr ועוד.
  • מעבר לעטיפה פשוטה של פונקציות, פייתון תומכת גם בדפוסי דקורטורים מתקדמים. אחד הדוגמאות הבולטות הוא @property, שהופך מתודה למאפיין מחושב – ומשתמשים בו לרוב יחד עם @<property>.setter ו-@<property>.deleter.

דקורטורים יכולים לשמש גם כ-מחוללי דקורטורים (decorator factories) – כלומר, דקורטורים שמקבלים פרמטרים בעצמם באמצעות עטיפה נוספת.

איטרטורים וגנרטורים

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

  • __iter__() – מחזירה את האובייקט עצמו כאיטרטור
  • __next__() – מחזירה את הפריט הבא, או מעלה חריגת StopIteration כאשר אין פריטים נוספים

בפייתון, כל אובייקט שאפשר לעבור עליו בלולאת for הוא או איטרטור בעצמו, או שיש לו מתודה __iter__ שמחזירה איטרטור. מבני הלולאה של פייתון, כמו גם פונקציות מובנות רבות (כמו sum(), list() ועוד), משתמשים בפרוטוקול הזה כדי לעבור על איברים.

אמנם ניתן לממש איטרטורים באופן ידני (כמו בדוגמת הפיבונאצ’י שראינו קודם), אבל פייתון מספקת כלי נוח יותר ליצירת איטרטורים – גנרטורים.

גנרטור הוא סוג מיוחד של איטרטור, שנכתב כפונקציה המשתמשת בפקודת yield כדי להחזיר סדרת ערכים בצורה "עצלנית" (lazy) – כלומר, כל ערך מחושב רק כשמבקשים אותו.

כאשר קוראים לפונקציית גנרטור, היא מחזירה אובייקט גנרטור שמממש אוטומטית את __iter__ ו-__next__. כל פעם שהפונקציה מגיעה ל-yield, היא עוצרת את הביצוע, שומרת את המצב, וממשיכה מהמקום הזה בקריאה הבאה.

דוגמה – פונקציית גנרטור

הנה גרסה שקולה לרצף פיבונאצ'י באמצעות גנרטור:

איטרטורים וגנרטורים

הגנרטור fib generator מחזיר רצף אינסופי של מספרי פיבונאצ'י, בדומה למחלקה שהצגנו קודם – אבל עם הרבה פחות קוד. כל קריאה ל-next(fib) מריצה את הפונקציה עד לפקודת yield הבאה, ואז עוצרת את הביצוע.

ביטויי גנרטור (generator expressions) מציעים תחביר מקוצר, בדומה לרשימות comprehension – אך במקום להחזיר רשימה, הם מחזירים גנרטור.
למשל:

python

squares = (x*x for x in range(10))

יוצר גנרטור שמחזיר את ריבועי המספרים מ-0 ועד 81.
שיטה זו חסכונית בזיכרון במיוחד כאשר עובדים עם רצפים גדולים, כי הפריטים מחושבים "תוך כדי תנועה" ולא נשמרים כולם בזיכרון.

גנרטורים ואיטרטורים הם כלים בסיסיים לעבודה עם זרמי מידע (streams), מערכי נתונים גדולים, או כאשר רוצים להשתמש בהערכה עצלה (lazy evaluation) בפייתון.
המודול itertools שבספריית התקן מספק כלים רבים ליצירה ושילוב של איטרטורים – כולל דפוסים מתקדמים של איטרציה, כמו מונים אינסופיים, קומבינטוריקה, חלוקה לקבוצות (batching) ועוד.

שווה גם להכיר את מנגנון ההאצלה בגנרטורים באמצעות התחביר yield from (שהוצג ב-PEP 380).
תחביר זה מאפשר לגנרטור להחזיר את כל הערכים מתוך iterable אחר או גנרטור תת-משני, ובכך מקל על חיבור בין גנרטורים שונים.

מנהלי הקשר והפקודה with

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

פרוטוקול מנהל הקשר כולל שתי מתודות:

  • __enter__: מופעלת בכניסה לבלוק של with
  • __exit__: מופעלת ביציאה מהבלוק (גם אם הייתה חריגה)

אובייקט שמממש את שתי המתודות האלה נקרא מנהל הקשר, וניתן להשתמש בו בתוך הפקודה with.
כאשר נכנסים לבלוק with, פייתון קוראת ל-__enter__, ואם יש ערך שהוא מחזיר – הוא נשמר במשתנה אחרי as (אם קיים).
כאשר יוצאים מהבלוק – בין אם זה קרה בצורה רגילה או בגלל שגיאה – פייתון קוראת ל-__exit__, אשר בדרך כלל מטפלת בשחרור המשאבים.

המנגנון הזה מבטיח שהמשאבים ישתחררו תמיד – אפילו אם התרחשה שגיאה.

דוגמה פשוטה לכך היא פתיחת קובץ.
 אובייקט קובץ בפייתון הוא מנהל הקשר:

מנהלי הקשר והפקודה with

כאן, הפונקציה open() מחזירה אובייקט קובץ שיש לו את המתודות __enter__ (שמחזירה את אובייקט הקובץ עצמו) ו-__exit__ (שסוגרת את הקובץ). לכן, השימוש בתחביר with open(…) as f: הוא הדרך המקובלת והנכונה בפייתון לעבוד עם קבצים – כדי להבטיח שהם ייסגרו כראוי גם במקרה של שגיאות.

יצירת מנהלי הקשר מותאמים אישית

ניתן לממש את המתודות __enter__ ו-__exit__ גם במחלקות שאתם כותבים בעצמכם.
למשל, נניח שיש לנו אובייקט חיבור למסד נתונים, ואנחנו רוצים להשתמש במנהל הקשר כדי לבצע commit או rollback אוטומטיים לעסקאות:

 

מנהלי הקשר והפקודה with

בדוגמה הזו, המחלקה DatabaseConnection דואגת לכך שגם אם הבלוק מסתיים בהצלחה וגם אם מתרחשת שגיאה – העסקה במסד הנתונים תיסגר בצורה תקינה, והחיבור ייסגר.

הפרמטרים של __exit__ (exc_type, exc_val, exc_tb) מציינים האם החריגה (אם הייתה) היא זו שגרמה ליציאה מהבלוק – אם לא הייתה חריגה, שלושתם יהיו None.
אם __exit__ מחזירה True, החריגה תודחק (כלומר, תיחשב כאילו טופלה); לרוב מחזירים False כדי שהשגיאה תועבר הלאה ותגרום לחריגה רגילה.

כחלופה פשוטה יותר למקרים בסיסיים, ניתן להשתמש בדקורטור @contextmanager מתוך המודול contextlib.
הדקורטור הזה מאפשר לכתוב מנהל הקשר באמצעות תחביר של גנרטור – מחזירים ערך אחד באמצעות yield להפעלת הבלוק, ואז הקוד ממשיך לאחר ה-yield לביצוע פעולות הניקוי (cleanup).

שיטה זו לעיתים מובילה לקוד תמציתי וברור יותר.

המתודה Timer.__enter__ צריכה להפעיל טיימר בתחילת הבלוק, ו-Timer.__exit__ צריכה לעצור את הטיימר ולשמור את הזמן שחלף (ואולי גם לטפל או להתעלם מחריגות לפי הצורך).

קורס Python – רמיזות טיפוס (Type Hinting) והקלדה סטטית (Static Typing) בפייתון

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

רמיזות הטיפוס הוכנסו בפייתון 3.5 באמצעות PEP 484, ומאפשרות לציין סוגים צפויים עבור:

  • פרמטרים של פונקציות
  • ערכי החזרה מפונקציות
  • משתנים
  • שדות במחלקות

רמיזות הטיפוס אינן נאכפות בזמן ריצה על ידי פייתון – הן למעשה משמשות כהערות עבור המתורגמן.
אבל כלים כמו בודקי טיפוסים (למשל mypy), סורקים (linters), ועורכי קוד (IDEs) יכולים להשתמש בהן כדי לזהות שגיאות טיפוס עוד לפני הרצת הקוד.

תחביר בסיסי

ניתן להוסיף רמיזות טיפוס בהגדרת פונקציה כך:

רמיזות טיפוס (Type Hinting) והקלדה סטטית (Static Typing) בפייתון
 

בדוגמה הזו, name: str מציין ש־name אמור להיות מסוג מחרוזת (string), ו־-> str מציין שהפונקציה מחזירה מחרוזת.
בזמן ריצה, קריאה ל־greet(5) לא תגרום לשגיאת TypeError, כי פייתון לא אוכפת את הטיפוסים בפועל, אך בודק טיפוסים סטטי כן יזהה את זה כתקלה אפשרית.

רמיזות טיפוס למשתנים ושדות במחלקות

PEP 526 הציג תחביר חדש להוספת רמיזות טיפוס למשתנים:

python

age: int = 42

זה לא מגביל את המשתנה age להיות באמת int (אפשר עדיין לבצע age = "forty-two" בזמן ריצה),
אבל זה משמש כתיעוד, וכלי בדיקה יוכלו לאתר טעויות בהתאם.

המודול typing

המודול typing בפייתון מספק מגוון עשיר של טיפוסים למבנים מורכבים יותר:

  • טיפוסים גנריים ומבני נתונים: לדוגמה
    List[int], Dict[str, float], Tuple[int, str] – מאפשרים לציין את סוגי האיברים בתוך מבנים.
    (בפייתון 3.9 ואילך ניתן להשתמש בטיפוסים המובנים ישירות: list[int] במקום List[int]).
  • טיפוס אופציונלי:
    Optional[X] (או התחביר החדש X | None) מציין שערך יכול להיות מסוג X או None.
  • איחוד טיפוסים:
    Union[X, Y] (או X | Y בגרסה 3.10+) מציין שערך יכול להיות מסוג X או מסוג Y.
  • כינויים לטיפוסים:
    ניתן ליצור שם מקוצר לטיפוס מורכב, לדוגמה:
    Coordinate = Tuple[float, float]
  • טיפוסי פונקציות:
    Callable[[ArgType1, ArgType2], ReturnType] – מתאר את החתימה של פונקציה.
  • משתני טיפוס:
    מאפשרים לכתוב פונקציות או מחלקות גנריות – שמקבלות טיפוס כלשהו ומחזירות אותו, לדוגמה T.
  • מחלקות פרוטוקול (Protocol classes – לפי PEP 544):
    תומכות ב־duck typing עם בדיקות סטטיות – מאפשר לבדוק אם מחלקה תואמת לפרוטוקול מסוים מבלי לרשת אותו בפועל.

שימוש ברמיזות טיפוס יכול לשפר בצורה משמעותית את התחזוקה של קוד בפרויקטים גדולים.
כלים כמו mypy (בודק טיפוסים סטטי), Pyright / Pylance (ב־VSCode), או בדיקות הקוד של PyCharm,
יכולים לזהות אי-התאמות בטיפוסים, החזרות חסרות, שגיאות תחביר הקשורות לטיפוסים ועוד – על בסיס האנוטציות הללו.

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

דוגמה – שימוש ברמיזות טיפוס עם מחלקות נתונים

הדקורטור @dataclass (מהמודול dataclasses שהתווסף בפייתון 3.7+) מאפשר ליצור מחלקות שנועדו לאחסן נתונים.
הוא נשען במידה רבה על רמיזות טיפוס לצורך הגדרת השדות:

רמיזות טיפוס (Type Hinting) והקלדה סטטית (Static Typing) בפייתון

מטא-קלאסים: יצירת מחלקות באופן דינמי

מטא-תכנות

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

מטא-קלאסים: יצירת מחלקות באופן דינמי

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

python

class MyClass:

פייתון מריץ את ההגדרה הזו, והתוצאה היא אובייקט מטיפוס type (או תת-מחלקה שלו).

המחלקה type היא המטא-קלאס הברירת מחדל של פייתון – זו המחלקה שבונה מחלקות.
מטא-קלאס הוא פשוט: "מחלקה של מחלקות" – כלומר, מחלקה שהמופעים שלה הם מחלקות.

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

כדי ליצור מטא-קלאס, יוצרים מחלקה שיורשת מ־type, ומממשים את type.__new__ או type.__init__.
כאשר פייתון רואה הגדרת מחלקה עם הפרמטר metaclass=MyMeta, הוא ישתמש ב־MyMeta.__new__ כדי לבנות את אובייקט המחלקה.

דוגמה – שימוש בסיסי במטא-קלאס:

במקרה הזה, PrintMeta הוא מטא-קלאס. כאשר מציינים metaclass=PrintMeta במחלקה MyClass, בעת יצירת המחלקה פייתון קוראת למתודה __new__ של המטא-קלאס ומדפיסה הודעה.

מטא-קלאסים: יצירת מחלקות באופן דינמי

 

בדוגמה הזו אנחנו רק מתעדים את יצירת המחלקה, אך שימושים מעשיים כוללים:

  • אכיפת שדות או מתודות במחלקות – לדוגמה, לוודא שלמחלקה יש שדה מסוים או להוסיף מתודות אוטומטית.
  • רישום אוטומטי (Registry) – לדוגמה, כשמחלקה נוצרת, לרשום אותה באוסף גלובלי (כמו במערכות פלאגינים או ORMs).
  • ירושה דינמית או התאמה לאינטרפייסים – שינוי המחלקות הבסיסיות או הוספת mixins בזמן יצירה.
  • שימוש קלאסי: Django ORM – המטא-קלאס רושם את המודל מול Django ויוצר את השדות שהם descriptors.

מטא-קלאסים הם כלי עוצמתי אך עשויים להפוך את הקוד לפחות ברור. לעיתים קרובות ניתן להשיג את אותה המטרה עם דקורטורים למחלקות או פונקציות יצרניות פשוטות. השתמשו בהם במשורה ותתעדו היטב.

יצירת מחלקות דינמית עם type()

מטא-תכנות

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

יצירת מחלקות דינמית עם type()

לפונקציה המובנית type() יש שני שימושים:

  • type(obj) מחזירה את סוג האובייקט.
  • type(name, bases, attrs_dict) יוצרת מחלקה חדשה בזמן ריצה.

כך type כמטא-קלאס יוצר מחלקות מאחורי הקלעים.

דוגמה:

יצירת מחלקות דינמית עם type()

כאן אנחנו יוצרים מחלקה בזמן ריצה עם:

  • "DynamicHello" כשם המחלקה
  • (object,) כטווח ירושה
  • מילון attrs שבו מוגדרת המתודה greet

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

הוספת שדות ומתודות בזמן ריצה

גם מבלי להשתמש ישירות ב־type(), פייתון מאפשרת להוסיף שדות למחלקות ולאובייקטים תוך כדי ריצה:

python

שיטה זו גמישה אך עשויה לסבך ניפוי שגיאות אם נעשה בה שימוש לא זהיר.
לעיתים קרובות ניתן להשתמש בפתרונות פשוטים יותר כמו closures או factory functions.

ניהול גישה לשדות (Descriptors)

מטא-תכנות

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

Descriptors

Descriptors הם תכונה מתקדמת מאוד בפייתון, שמאפשרת שליטה בגישה לשדות במחלקות.
כל אובייקט שמממש אחת מהמתודות: __get__, __set__, או __delete__ נחשב ל־descriptor.
כאשר משתמשים בו כשדה במחלקה – פייתון מפעילה את המתודות האלו כשניגשים לשדה, משנים אותו או מוחקים אותו.

המנגנון הזה עומד מאחורי:

  • פונקציות שמתנהגות כמתודות באובייקטים
  • @property
  • ORMs כמו Django ו-SQLAlchemy (שדות בטבלה הם descriptors)

Descriptors

למשל, כאשר ניגשים ל־obj.attr, אם attr הוא descriptor, פייתון תקרא:

python

attr.__get__(obj, type(obj))

 

כנ"ל, השמה (obj.attr = value) תפעיל __set__.

שימושים נפוצים

  • תכונות מחושבות (@property) – למעשה descriptor שמאפשר גם getter, setter, ו־deleter.
  • בדיקת טיפוסים / ערכים – לדוגמה, לוודא ששדה הוא תמיד מספר חיובי.
  • טעינה עצלה (Lazy Loading) – קריאה ראשונה מבצעת חישוב או שאילתת DB, והשאר משתמשים בערך המזומן.
  • ORMs – בדנגו/SQLAlchemy, כל שדה כמו models.CharField הוא descriptor שמפעיל לוגיקה לגישה למסד.

דוגמה – Descriptor שמבצע בדיקת טיפוס

Descriptors

במקרה הזה, TypedAttribute מוודא שכל ערך שמוקצה לשדה הוא מהטיפוס המצופה.
השדות name ו־age במחלקה Person הם descriptors – כל השמה כמו self.name = name תפעיל את __set__.

הערכים נשמרים בפועל בתוך __dict__ של המופע.
המתודה __get__ מחזירה את הערך מ־__dict__, ו־__delete__ מונעת מחיקה של השדה.

פונקציות שמוגדרות בתוך מחלקות הן בעצמן descriptors – המתודה __get__ מחזירה מתודה "קשורה" לאובייקט (bound method) וזהו המנגנון שמאפשר שימוש ב־instance.method().

תכנות מקבילי ואסינכרוני (Concurrency and Asynchronous Programming)

מודלים של מקביליות

בתוכנה מודרנית יש לעיתים קרובות צורך לבצע משימות רבות בו-זמנית או לנהל הרבה פעולות באופן יעיל.
פייתון מספקת מספר מודלים של מקביליות:

  • threading – חוטים (threads)
  • multiprocessing – תהליכים נפרדים
  • asyncio – תכנות אסינכרוני מבוסס אירועים (event loop)

לכל אחד מהם יתרונות, חסרונות ושימושים מתאימים.

GIL – נעילת המפרש הגלובלית

ב־CPython, ה־GIL מונע מהרצת מספר חוטים (threads) בו-זמנית על קוד פייתון.
זה מפשט את ניהול הזיכרון – אך מהווה צוואר בקבוק לתוכניות שמעמיסות על המעבד (CPU-bound).
התוצאה היא ש־threads לא יכולים לפעול במקביל אמיתי על כמה ליבות מעבד כאשר מדובר בקוד פייתון טהור.

מקביליות מבוססת חוטים (Thread-Based Concurrency)

מודלים של מקביליות

בתוכנה מודרנית יש לעיתים קרובות צורך לבצע משימות רבות בו-זמנית או לנהל הרבה פעולות באופן יעיל.
פייתון מספקת מספר מודלים של מקביליות:

  • threading – חוטים (threads)
  • multiprocessing – תהליכים נפרדים
  • asyncio – תכנות אסינכרוני מבוסס אירועים (event loop)

לכל אחד מהם יתרונות, חסרונות ושימושים מתאימים.

GIL – נעילת המפרש הגלובלית

ב־CPython, ה־GIL מונע מהרצת מספר חוטים (threads) בו-זמנית על קוד פייתון.
זה מפשט את ניהול הזיכרון – אך מהווה צוואר בקבוק לתוכניות שמעמיסות על המעבד (CPU-bound).
התוצאה היא ש־threads לא יכולים לפעול במקביל אמיתי על כמה ליבות מעבד כאשר מדובר בקוד פייתון טהור.

מקביליות מבוססת חוטים (Thread-Based Concurrency)

Threads מאפשרים לתוכנית להריץ כמה זרמי פיקוד (flows) באותו תהליך.
המודול threading בפייתון מספק ממשק פשוט ליצירת חוטים.

אפשר ליצור thread ע"י:

  • יצירת מופע של threading.Thread(target=func)
  • או ירושה מהמחלקה Thread ומימוש המתודה run()

אבל:
חשוב להבין – בגלל ה־GIL, רק חוט אחד מריץ קוד פייתון בכל רגע נתון.
לכן:

  • במשימות שתלויות ב־I/O (כמו קריאה מרשת או קובץ) – threads כן יעילים.
  • במשימות כבדות למעבד (CPU-bound) – threads לא ינצלו יותר מליבה אחת, ולכן לא יועילו הרבה.
    מקביליות מבוססת חוטים (Thread-Based Concurrency)
     

כאן, t1 ו-t2 יריצו את הפונקציות שלהם באופן שיתחלף ביניהם (interleave) – כלומר, הם ידפיסו מספרים לסירוגין.
בשל ה־GIL, הם לא ירוצו באמת בו־זמנית על מעבדים שונים, אך פייתון תעבור ביניהם בנקודות החלפת הקשר (context switch), כמו בזמן פעולות קלט/פלט או לאחר מספר מסוים של הוראות Bytecode.
ובכל זאת, הדבר עשוי לייעל משימות שתלויות בקלט/פלט (למשל קריאה משני התקנים איטיים במקביל).

בטיחות חוטים (Thread Safety)

מודלים של מקביליות

בתוכנה מודרנית יש לעיתים קרובות צורך לבצע משימות רבות בו-זמנית או לנהל הרבה פעולות באופן יעיל.
פייתון מספקת מספר מודלים של מקביליות:

  • threading – חוטים (threads)
  • multiprocessing – תהליכים נפרדים
  • asyncio – תכנות אסינכרוני מבוסס אירועים (event loop)

לכל אחד מהם יתרונות, חסרונות ושימושים מתאימים.

GIL – נעילת המפרש הגלובלית

ב־CPython, ה־GIL מונע מהרצת מספר חוטים (threads) בו-זמנית על קוד פייתון.
זה מפשט את ניהול הזיכרון – אך מהווה צוואר בקבוק לתוכניות שמעמיסות על המעבד (CPU-bound).
התוצאה היא ש־threads לא יכולים לפעול במקביל אמיתי על כמה ליבות מעבד כאשר מדובר בקוד פייתון טהור.

בטיחות חוטים (Thread Safety)

כאשר מספר חוטים פועלים במקביל וניגשים לנתונים משותפים – חייבים להבטיח גישה בטוחה, אחרת עלולים להיווצר מצבי תחרות (race conditions).

פייתון מספקת כלים לסנכרון כמו:

  • threading.Lock (נעילה בסיסית)
  • RLock (נעילה חוזרת)
  • Semaphore
  • Event
  • Condition

Thread Safety

בדוגמה זו, אנו דואגים שרק חוט אחד בכל פעם יוכל לשנות את המשתנה shared counter ע"י שימוש ב־lock.
ללא נעילה, עלולות להתרחש התנגשות בין חוטים והעדכונים לא יישמרו כראוי.

ThreadPoolExecutor – תזמון פשוט של משימות מקביליות

למשימות פשוטות יותר, ניתן להשתמש ב־concurrent .futures ,ThreadPoolExecutor
המאפשר לשלוח משימות (callables) לבריכת חוטים ולקבל תוצאה באמצעות Future.

מתי להשתמש בחוטים?

  • כאשר יש משימות שתלויות בקלט/פלט (I/O-bound)
  • כאשר נדרשת תגובתיות (למשל ב־GUI או שרת שמטפל בבקשות)
  • לא מתאים למשימות כבדות למעבד (CPU-bound) – לשם כך עדיף להשתמש בתהליכים (multiprocessing) או בקוד חיצוני (C/Cython) שמשחרר את ה־GIL.

הרצה מקבילית מבוססת תהליכים (Process-Based Parallelism)

מודלים של מקביליות

בתוכנה מודרנית יש לעיתים קרובות צורך לבצע משימות רבות בו-זמנית או לנהל הרבה פעולות באופן יעיל.
פייתון מספקת מספר מודלים של מקביליות:

  • threading – חוטים (threads)
  • multiprocessing – תהליכים נפרדים
  • asyncio – תכנות אסינכרוני מבוסס אירועים (event loop)

לכל אחד מהם יתרונות, חסרונות ושימושים מתאימים.

GIL – נעילת המפרש הגלובלית

ב־CPython, ה־GIL מונע מהרצת מספר חוטים (threads) בו-זמנית על קוד פייתון.
זה מפשט את ניהול הזיכרון – אך מהווה צוואר בקבוק לתוכניות שמעמיסות על המעבד (CPU-bound).
התוצאה היא ש־threads לא יכולים לפעול במקביל אמיתי על כמה ליבות מעבד כאשר מדובר בקוד פייתון טהור.

הרצה מקבילית מבוססת תהליכים (Process-Based Parallelism)

כדי לנצל באמת את כל ליבות המעבד עבור משימות כבדות, יש להשתמש ב־multiprocessing.
מודול זה מאפשר יצירת תהליכים נפרדים – כל תהליך מריץ מפרש פייתון נפרד עם זיכרון משלו.
לכן, אין GIL משותף, ומשימות כבדות למעבד יכולות לרוץ באמת במקביל.

הממשק של multiprocessing דומה מאוד לזה של threading, עם מחלקות כמו:

  • Process – בדומה ל־Thread
  • Pool
  • concurrent.futures.ProcessPoolExecutor – ממשק פשוט יותר

דוגמה לשימוש ב־multiprocessing

הרצה מקבילית מבוססת תהליכים (Process-Based Parallelism)
 

נקודות חשובות לגבי multiprocessing

  • ב-Windows (ובמערכות נוספות) תהליך חדש נוצר ע"י ייבוא המודול הראשי מחדש – לכן חובה להשתמש ב־if __name__ == "__main__" כדי למנוע יצירה רקורסיבית של תהליכים.
  • הנתונים בין תהליכים מבודדים – כדי לשתף מצב צריך להשתמש ב־IPC כמו Queue, Pipe, או multiprocessing.Value, Array.פתיחת תהליך יקרה יותר מ־thread – לכן מתאימה למשימות כבדות שדורשות מקביליות אמיתית.
  • קיימת גרסה בשם multiprocessing.dummy – זו עטיפה סביב threading לצורך תאימות ממשק.
  • ניתן גם להשתמש בספריות גבוהות יותר כמו joblib או pathos שמספקות ממשק נוח למקביליות.

שילוב נכון בין Threads, Async ו־Processes בהתאם לאופי המשימה – הוא המפתח לכתיבה יעילה של תוכנה מקבילית בפייתון.

שימוש ב־ProcessPoolExecutor מתוך concurrent.futures:

הרצה מקבילית מבוססת תהליכים (Process-Based Parallelism)
 

שימוש זה מפעיל בריכה של תהליכים (worker processes) ואוסף את התוצאות מאובייקטי Future.
המחלקה ProcessPoolExecutor דואגת בעצמה להקמה ולסיום של הבריכה.
מומלץ להשתמש במקביליות מבוססת תהליכים (processes) עבור משימות כבדות למעבד (CPU-bound) – כמו חישובים מתמטיים כבדים, עיבוד תמונה, וכו', שבהן ה־GIL מגביל את השימוש ב־threads.

בנוסף, אפשר גם לשקול ספריות שמרפות את ה־GIL, כמו NumPy, אשר מבצעת חישובים פנימיים בקוד C מרובה־חוטים.

תכנות אסינכרוני עם asyncio

הספרייה asyncio של פייתון (הוצגה בגרסה 3.4 והורחבה עם התחביר async/await בגרסה 3.5) מספקת תשתית לתכנות אסינכרוני מבוסס קלט/פלט באמצעות לולאת אירועים (event loop).

בניגוד ל־threading או multiprocessing, asyncio פועל בשיטה של ריבוי משימות שיתופי (cooperative multitasking), בדומה למה שקיים ב־Node.js או שפות כמו JavaScript / C#.

מושגים מרכזיים ב־asyncio

  • קורוטינות (coroutines): פונקציות שמוגדרות עם async def, שיכולות להשתמש ב־await על פעולות אסינכרוניות אחרות.
  • await: משמש בתוך קורוטינה כדי "להחזיר שליטה" ללולאת האירועים עד שהפעולה מסתיימת.
  • לולאת אירועים (event loop): הלב של asyncio שמנהל את הקורוטינות ומריץ אותן. לרוב ניגשים אליו עם asyncio.get_event_loop() או פשוט משתמשים ב־asyncio.run().
  • משימות (Tasks): קורוטינות שהוזמנו להרצה מקבילה ע"י asyncio.create_task(coro()). משימה היא עטיפה סביב קורוטינה, בדומה ל־Promise/ Future.

דוגמה – בסיסי asyncio

תכנות אסינכרוני עם asyncio
 

בדוגמה זו, say_after היא קורוטינה שמבצעת השהייה ואז מדפיסה הודעה.
בפונקציה main, אנחנו מזמנים שתי קורוטינות בצורה אסינכרונית עם create_task.
הן מתחילות לרוץ מיד – והלולאת אירועים יכולה להריץ קוד אחר בינתיים.

התוצאה: "hello" יודפס אחרי 2 שניות, "world" אחרי 3 שניות – והזמן הכולל הוא כ־3 שניות (ולא 5) כי ההמתנות התרחשו במקביל.

השוואה בין AsyncIO ל-Threads

Async IO לעומת Threads:

נושאAsyncIOThreads
שיטת פעולהריבוי משימות שיתופי (cooperative)ריבוי משימות טרום־אמפיטיבי (preemptive)
צריכת זיכרוןחסכוני יותר – תהליך יחידכל thread צורך stack משלו
שימוש במשאביםמעולה לקלט/פלט (I/O-bound)טוב ל־I/O, אך מוגבל ע"י GIL ב־CPU
שימוש ב־CPU רב ליבותלא – תהליך יחידמוגבל ע"י GIL בפייתון
קריאות חסומותחוסמות את כל הלולאהרק חוט אחד נחסם

שילוב קוד async עם קוד סינכרוני

לא ניתן לקרוא ל־await מחוץ לפונקציה אסינכרונית.
יש להריץ קורוטינות דרך לולאת אירועים באמצעות asyncio.run() או loop.run_until_complete().

לעיתים, כדאי לשלב בין חוטים ו־asyncio – למשל להפעיל לולאת אירועים בחוט נפרד.
ספריות כמו quart (גרסה אסינכרונית של Flask) או FastAPI (מבוססת Starlette) משתמשות ב־asyncio לניהול בקשות.

לולאת אירועים ו־Futures

לולאת האירועים היא הליבה של asyncio.
זו לולאה אינסופית שמנהלת סט של משימות (קורוטינות, Futures, callbacks), ודואגת להריץ כל אחת כשהיא מוכנה.

כאשר קורוטינה מבצעת await על פעולה (למשל sleep או I/O), הלולאה יודעת שהמשימה מחכה, ויכולה להריץ משימות אחרות meantime.

Futures / Promises

ב־asyncio, Future הוא אובייקט שמייצג תוצאה שעדיין לא זמינה.
בדומה ל־Promise ב־JavaScript.

לרוב לא יוצרים Future בעצמכם – אלא משתמשים במבנים ברמה גבוהה יותר (כמו create_task שמחזיר Task – תת־מחלקה של Future).

לולאת אירועים ו־Futures
 

הפונקציה gather מריצה את כל הקורוטינות במקביל, ומחזירה את כל התוצאות ברשימה אחת לפי הסדר.

השימוש ב־asyncio.gather מתאים כאשר רוצים לבצע מספר פעולות I/O במקביל ולחכות שכולן יסתיימו.

זה יריץ את כל הקורוטינות של fetch_data כמעט בו זמנית.

כל אחת תישן למשך n שניות, כלומר: אחת תישן 0 שניות, השנייה 1, וכן הלאה עד 4.
הזמן הכולל להרצה יהיה כ-4 שניות (הקורוטינה האיטית ביותר), ולאחר מכן תודפס רשימת התוצאות.
gather מחזירה את התוצאות לפי הסדר שבו הועברו הקורוטינות.

ביטול משימות

אם משימה עלולה לרוץ זמן רב, אפשר לבטל אותה עם task.cancel().
זה יזרוק חריגת CancelledError בנקודת ההמתנה (await) הבאה בתוך הקורוטינה.
ניתן ללכוד את asyncio.CancelledError כדי לבצע פעולות ניקוי (cleanup) אם נדרש.

מנהלי הקשר ואיטרטורים אסינכרוניים

פייתון תומכת גם ב־async with ו־async for באמצעות מימוש של __aenter__, __aexit__, ו־__anext__.
זה שימושי כאשר עובדים עם משאבים אסינכרוניים – לדוגמה, פתיחת חיבור לרשת או למסד נתונים בצורה אסינכרונית.

מתי כדאי להשתמש ב־asyncio

כאשר יש הרבה פעולות I/O מקבילות (קריאות לרשת, קבצים, מסדי נתונים וכו’).
במקרים כאלה, asyncio מאפשר טיפול באלפי משימות בו זמנית מבלי הצורך ביצירת חוטים (threads), דבר שחוסך משאבים.
החיסרון: הקוד הופך להיות אסינכרוני לחלוטין – כל פונקציה צריכה להיות async, והקריאות הן await.

משימות שדורשות כוח עיבוד (CPU-bound) אינן מתאימות ל־async – כי כל הקוד עדיין רץ בלולאה אחת.
במקרים כאלה, אפשר לשלב עם multiprocessing או להעביר משימות לבריכת חוטים עם loop.run_in_executor.

הבסיס לחישובים מספריים (NumPy)

פייתון הפכה לשפה המרכזית עבור AI ולמידת מכונה – בזכות הפשטות שלה והמערכת האקולוגית העשירה של ספריות.

NumPy – הבסיס לחישובים מספריים

NumPy היא ספרייה בסיסית במדעי הנתונים בפייתון.
היא מספקת את ndarray – מערך רב-ממדי יעיל, ואת כל הפונקציות לעבודה מהירה עם מערכים.

תכונות מרכזיות

  • מערכים אחידים (ndarray) – כל הערכים מאותו סוג (לרוב מספרים)
  • חישובים וקטוריים – הרבה יותר מהירים מלולאות בפייתון
  • שידור (broadcasting) – התאמת צורות של מערכים לחישוב
  • אלגברה ליניארית, מספרים אקראיים, טרנספורמים, ועוד

דוגמה

הבסיס לחישובים מספריים (NumPy)

שידור (Broadcasting)

פייתון הפכה לשפה המרכזית עבור AI ולמידת מכונה – בזכות הפשטות שלה והמערכת האקולוגית העשירה של ספריות.

שידור (Broadcasting)

python

x = np.array([1, 2, 3])

y = 5

print(x + y)  # [6 7 8]

עיבוד מערכים

NumPy כולל פונקציות לשינוי צורה, חיתוך, אינדוקס מתוחכם ומסיכות בוליאניות.
למשל:

python

arr[arr < 0] = 0  # הפיכת ערכים שליליים ל־0

ניתוח ועיבוד נתונים (Pandas)

פייתון הפכה לשפה המרכזית עבור AI ולמידת מכונה – בזכות הפשטות שלה והמערכת האקולוגית העשירה של ספריות.

Pandas – ניתוח ועיבוד נתונים

Pandas מספקת מבנים ברמה גבוהה (DataFrame, Series) לעבודה נוחה עם נתונים טבלאיים ומובנים.

מבנים עיקריים

  • DataFrame– טבלה דו-ממדית עם שמות שורות ועמודות
  • Series – עמודה בודדת עם תוויות

דוגמא

 ניתוח ועיבוד נתונים (Pandas)
 

פעולות נפוצות

  • סינון: df[condition]
  • חיבור טבלאות: merge
  • קיבוץ וסטטיסטיקה: groupby
  • שינוי מבנה: pivot, melt
  • עבודה עם סדרות זמן

קריאה וכתיבה

python

pd.read_csv, pd.read_excel, df.to_csv, df.to_excel

מתי להשתמש ב־Pandas?

פייתון הפכה לשפה המרכזית עבור AI ולמידת מכונה – בזכות הפשטות שלה והמערכת האקולוגית העשירה של ספריות.

Pandas – ניתוח ועיבוד נתונים

Pandas מספקת מבנים ברמה גבוהה (DataFrame, Series) לעבודה נוחה עם נתונים טבלאיים ומובנים.

מתי להשתמש ב־Pandas?

כשיש לכם נתונים טבלאיים (כמו קבצי CSV, נתוני מסד) או סדרות זמן – Pandas הוא הכלי הראשון שכדאי לפנות אליו.
עבור עיבוד ברמת איברים (element-wise), NumPy מהיר יותר, אך Pandas נוח יותר כשיש שילוב של סוגי נתונים ותוויות.

scikit-learn – למידת מכונה בקלות

scikit-learn (או בקצרה sklearn) היא ספרייה פופולרית ללמידת מכונה קלאסית – לא למידה עמוקה.
כוללת אלגוריתמים כמו רגרסיה, סיווג, אשכולות, הפחתת מימדים, ועוד.

תכונות מרכזיות

  • API עקבי: כל אלגוריתם הוא "אומדן" (Estimator) עם .fit(X, y) ו־.predict(X)
  • תומך בקלט מסוג NumPy או Pandas
  • Pipelines: שילוב של קדם-עיבוד ואלגוריתם במבנה אחד
  • חיפוש פרמטרים: GridSearchCV עם קרוס-ולידציה

דוגמה

מתי להשתמש ב־Pandas?
 

scikit-learn

הוא הבחירה הנכונה ללמידת מכונה קלאסית כאשר נדרש פתרון מהיר, פשוט ואמין לבעיות כמו סיווג, רגרסיה או אשכולות.

הוא לא מיועד לרשתות נוירונים עמוקות – שם משתמשים ב־TensorFlow או PyTorch.

מיקרו־פריימוורק קליל (Flask)

פיתוח אתרים בפייתון

פייתון היא בחירה פופולרית לפיתוח אתרי אינטרנט ו־APIs. קיימות מסגרות עבודה (Frameworks) רבות – החל ממינימליסטיות ועד לפתרונות שלמים – שמתאימות לצרכים שונים. בפרק זה נסקור את Flask, Django ו־FastAPI, נדון בבניית שירותי REST ו־GraphQL, ניגע בשיקולי אבטחה, ונבחן אסטרטגיות לפריסה (deployment) של אפליקציות ווב בפייתון.

Flask: מיקרו־פריימוורק קליל

Flask היא מסגרת בסיסית מאוד לפיתוח ווב. היא לא כופה מבנה מסוים ומשאירה למפתח את הבחירה בטכנולוגיות נלוות (מסד נתונים, ולידציה, וכו').
Flask כוללת ניתוב (routing), טיפול בבקשות/תגובות, ומנוע תבניות (Jinja2).

דוגמה בסיסית

Flask: מיקרו־פריימוורק קליל
 

הסבר

  • /hello מחזיר מחרוזת.
  • /add מקבל JSON עם a ו־b, ומחזיר את הסכום.
  • debug=True מפעיל שרת פיתוח.

מה מתאים ל-Flask

  • בניית APIs
  • שירותים קטנים-בינוניים
  • מיקרו־שירותים

ניתן להוסיף הרחבות כמו Flask-SQLAlchemy למסדי נתונים, Flask-Login לאימות, ועוד.

פריימוורק שלם ועוצמתי (Django)

Django פועלת בגישת "כולל סוללות" – הכל כלול: ORM, אימות משתמשים, מנוע תבניות, ממשק ניהול ועוד.

מושגים מרכזיים

  • Models: מגדירים את מבנה הנתונים כמחלקות.
  • Views: הלוגיקה של הבקשות.
  • Templates: תצוגות HTML עם משתנים.
  • URLconf: מיפוי כתובות לפונקציות.
  • Forms: מערכת לטפסים וולידציה.
  • Admin: ניהול מודלים מהדפדפן.
  • Migrations: ניהול שינויים בסכמת המסד.

דוגמה

פריימוורק שלם ועוצמתי (Django)

חוזקות Django

  • מתאים מאוד לפרויקטים גדולים ועשירים בתוכן
  • כלי ניהול אוטומטי
  • מבנה קוד מסודר ותחזוקתי

חסרון Django

עבור פרויקטים קטנים, עלול להיות כבד מדי.

פריימוורק מודרני (FastAPI) לבניית APIs

FastAPI נועדה לפיתוח מהיר של APIs מודרניים עם תמיכה מובנית ב־async, תיעוד אוטומטי וביצועים גבוהים.

תכונות עיקריות

  • תיעוד אוטומטי: Swagger UI ו־OpenAPI ב־/docs
  • שימוש ב־Pydantic לאימות נתונים
  • ביצועים גבוהים: מבוסס ASGI, מתאים לעומסי I/O
  • שימוש נרחב בטייפים (type hints) כולל injection של תלות (כמו DB, משתמש נוכחי וכו')

דוגמה

 פריימוורק מודרני (FastAPI) לבניית APIs
 

FastAPI מתאימה

  • פיתוח APIs מבוססי JSON
  • שרתים לאירוח מודלים של AI/ML
  • עבודה עם נתונים רבים ב־I/O מקביל

בניית APIs לפי REST

בניית APIs לפי REST – עקרונות

  • שימוש בשמות עצם ב־URL (לא פעלים): /customers/123 ולא /getCustomer
  • שימוש ב־HTTP Methods:
    • GET – שליפה
    • POST – יצירה
    • PUT/PATCH – עדכון
    • DELETE – מחיקה
  • קודי סטטוס מתאימים: 200, 201, 404, 400, 500
  • תמיכה ב־filtering, sorting, pagination
  • מבני JSON עקביים

כלים

  • Flask: Flask-RESTful, Flask-RESTX
  • Django: Django REST Framework (DRF)
  • FastAPI: מובנה כחלק מהפריימוורק

אימות והרשאות (Authentication & Authorization)

  • Flask: Flask-JWT-Extended, Flask-Login
  • Django: מערכת מובנית + DRF עם Token/JWT
  • FastAPI: תמיכה מובנית ב־OAuth2 (fastapi.security)

תוכן עניינים

מלאו פרטים ונחזור אליכם בהקדם
למדו מהמומחים שלנו
קורסים נוספים
למה לבחור בכרמל הדרכה?
אנחנו מציעים פתרונות איכותיים להדרכות מקצועיות שחוסכות לכם זמן ומשאבים, ומספקים לכם את הכלים לקחת את הכישורים שלכם צעד קדימה!
carmel website
מרצים מובילים

בעלי ניסיון הדרכתי
ומעשי עשיר

carmel website
מגיעים אליכם

אתם קובעים את
מיקום הקורס והמועד

carmel website
תאוריה ותרגול

חומרי לימוד ומעבדות
רשמיות של מיקרוסופט הזמינים בענן

carmel website
תוכנית מותאמת

התאמה מלאה ואישית
לדרישות ולצרכי הארגון

מתחיל ב-17.07.2025

2 מפגשים

09:00-16:00
דילוג לתוכן