• בלוג
  • סנטינל בפייתון 3.15

סנטינל בפייתון 3.15

12/10/2026

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

ויחד איתם פיצ'ר אחד בשם sentinel שאני בכלל לא בטוח שעדיין נחוץ.

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

def first_index(needle, haystack):
    for index, item in enumerate(haystack):
        if item == needle:
            return index

אם אני מחפש והפריט נמצא ברשימה הפונקציה תחזיר את האינדקס שלו. אם אני מחפש והפריט אינו ברשימה היא תחזיר None:

print(first_index('a', ['x', 'y', 'a', 'b', 'a']))
2

print(first_index('foo', ['x', 'y', 'a', 'b', 'a']))
None

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

דוגמה טובה היא הפונקציה next של פייתון שמחזירה את הדבר הבא מאיטרטור:

>>> items = iter(['a', 'b', 'c'])
>>> print(next(items))
a
>>> print(next(items))
b
>>> print(next(items))
c
>>> print(next(items))
Traceback (most recent call last):
  File "<python-input-4>", line 1, in <module>
    print(next(items))
          ~~~~^^^^^^^
StopIteration

קריאה ל next אחרי שהאיטרטור נגמר זורקת חריג בשם StopIteration כי אין לו יותר מה להחזיר. הפונקציה next עצמה לא יכולה להחזיר זקיף כי כל ערך שנבחר היה יכול להופיע באופן רגיל בערך ההחזר שלה.

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

>>> items = iter(['a', 'b', 'c'])
>>> print(next(items, None))
a
>>> print(next(items, None))
b
>>> print(next(items, None))
c
>>> print(next(items, None))
None
>>> print(next(items, None))
None
>>> print(next(items, None))
None
>>>

כך שאם אתם כן צריכים את הכתיבה בלי ה Exception יש פיתרון.

ומה לגבי sentinel? בעיקר לא מזיק:

>>> items = iter(['a', 'b', 'c'])
>>> missing = sentinel('MISSING')
>>> print(next(items, missing))
a
>>> print(next(items, missing))
b
>>> print(next(items, missing))
c
>>> print(next(items, missing))
MISSING
>>> print(next(items, missing))
MISSING
>>> print(next(items, missing))
MISSING
>>> next(items, missing) is missing
True
>>>

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

>>> x = sentinel('x')
>>> y = sentinel('x')
>>> z = x
>>> x is x
True
>>> x is z
True
>>> x is y
False
>>>

אז מה הבעיה עם הפיצ'ר? אני חושב שהוא פשוט מיותר:

  1. המנגנונים הקיימים כמו להחזיר None או לזרוק שגיאה מכסים את רוב המקרים.

  2. אם בכל זאת חייבים ערך מיוחד שיהיה שונה מ None אפשר להגדיר לבד class.

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