זה מה שקורה כששוכחים להשתמש ב with
פייתון הפתיע אותי היום עם הודעת השגיאה הבאה:
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.