• בלוג
  • זה מה שקורה כששוכחים להשתמש ב with

זה מה שקורה כששוכחים להשתמש ב with

09/04/2019

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

פייתון הפתיע אותי היום עם הודעת השגיאה הבאה:

Traceback (most recent call last):
  File "...", line 31, in search
    if is_text_in_file(file, word):
  File "", line 10, in is_text_in_file
    for line in fileinput.input(file):
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/fileinput.py", line 93, in input
    raise RuntimeError("input() already active")
RuntimeError: input() already active

וזאת הפונקציה שגרמה לבעיה:

def is_text_in_file(file, text):
    for line in fileinput.input(file):
        if text in line:
            return True

    return False

הפונקציה עובדת לא רע בפעם הראשונה שקוראים לה, אבל בגלל ה return באמצע לולאת ה fileinput, ברגע שמחזירים True בפעם הראשונה אי אפשר יותר לקרוא לה. הפונקציה יוצאת לפני שסגרה את הקובץ.

כיוון אחד לתקן את זה הוא להוסיף קריאה יזומה ל fileinput.close לפני ה return. וזה עובד:

def is_text_in_file(file, text):
    for line in fileinput.input(file):
        if text in line:
            fileinput.close()
            return True

    return False

אבל בינינו למה להתאמץ כשאפשר לתת ל Python לעבוד בשבילנו? כיוון הרבה יותר טוב יהיה לעטוף את כל הבלוק שמשתמש ב fileinput בפקודת with:

def is_text_in_file(file, text):
    with fileinput.input(file) as f:
        for line in f:
            if text in line:
                return True

    return False

אז נכון זה הוסיף עוד רמה של אינדנטציה לפונקציה, אבל פיתרון כזה מוודא שה File Input יסגר גם אם הפונקציה תזרוק Exception וגם אם בעתיד שינויים בקוד יבילו לסדר קריאות שונה. כלל אצבע שכדאי לזכור - כל פעם שאתם "תופסים" משאבים חשוב לבדוק איפה אתם משחררים אותם, והכי טוב לתת לפייתון לשבור את הראש ולשחרר את המשאבים בשבילכם. זו המטרה המרכזית של פקודת with.