2.24. מנהלי הקשר¶
פקודת ה-with מריצה קוד הכנה, אחר כך גוף, ואחר כך קוד פירוק – עם הבטחה שהפירוק ירוץ גם כאשר הגוף נכשל באמצע. צמד המתודות שמספק את ההכנה ואת הפירוק נקרא מנהל הקשר.
הצורה היא:
with <expression> as <name>:
<body>
הביטוי מחזיר מנהל הקשר. Python קוראת למתודה __enter__ שלו, אופציונלית מקשרת את התוצאה ל-<name>, מריצה את הגוף, ואחר כך קוראת ל-__exit__ – בין אם הגוף הושלם כרגיל ובין אם זרק חריגה.
__exit__ רץ בסוף הבלוק בכל מצב שיקרה בתוכו.¶
2.24.1. שימוש במנהל הקשר¶
הדוגמה הקנונית היא פתיחת קובץ:
with open("data.txt") as f:
text = f.read()
# f is now closed, even if read() failed
open() מחזיר אובייקט קובץ שהוא בעצמו מנהל הקשר; __enter__ מחזיר את הקובץ, ו-__exit__ סוגר אותו. בלוק ה-with הופך את ”תמיד לסגור את הקובץ בסיום“ לברירת מחדל במקום למשהו שהקורא צריך לזכור.
2.24.1.1. מנהלי הקשר מרובים¶
פקודת with יחידה יכולה להיכנס למספר מנהלי הקשר בבת אחת, מופרדים בפסיקים:
with open("input.txt") as src, open("output.txt", "w") as dst:
dst.write(src.read())
שקול לשני בלוקי with מקוננים, אך שטוח יותר. נכנסים למנהלים משמאל לימין ויוצאים מהם בסדר הפוך; אם __enter__ של המנהל הימני זורק חריגה, ה-__exit__ של המנהל השמאלי עדיין רץ.
2.24.2. כתיבת מנהל הקשר¶
כל מחלקה עם מתודות __enter__ ו-__exit__ עובדת כמנהל הקשר:
class Section:
def __init__(self, label):
self.label = label
def __enter__(self):
print("---", self.label, "---")
return self
def __exit__(self, exc_type, exc_value, traceback):
print("--- end", self.label, "---")
return False
with Section("setup"):
print("doing the work")
פלט:
--- setup ---
doing the work
--- end setup ---
__exit__ מקבל שלושה ארגומנטים המתארים את החריגה שסיימה את הבלוק, או שלושה ערכי None אם הבלוק הושלם כרגיל. החזרת False (או None) מאפשרת לכל חריגה להתפשט לאחר הפירוק; החזרת True תבלע אותה.
השתמשו במנהלי הקשר עבור כל משאב שיש לו מחזור חיים של ”פתיחה / סגירה“ או ”השגה / שחרור“ – לא רק קבצים. הדפוס שומר את הניקוי מצומד להכנה בנקודה שבה שניהם מוצגים, כך שסגירה נשכחת באמצע פונקציה ארוכה אינה יכולה לדלוף את המשאב.