בפייתון, אפשר ללכוד את מה שמוצג על המסך דרך הפקודה print()
.
אני אראה איך לפתור את המשימה הזו באלגנטיות – ללא תלויות חיצוניות, באמצעות הספרייה הסטנדרטית וכמה שורות קוד בודדות.
Contents
📦 הקשר קצר: לכידת stdout
הדרך הפשוטה ביותר היא להקצות מחדש באופן זמני את sys.stdout
לאובייקט io.StringIO()
בתוך מנהל הקשר (context manager):
from contextlib import contextmanager
import sys
import io
@contextmanager
def capture_stdout():
old_stdout = sys.stdout
sys.stdout = buffer = io.StringIO()
try:
yield buffer
finally:
sys.stdout = old_stdout
דוגמת שימוש:
with capture_stdout() as out:
print("זהו פלט שנלכד")
print("התוצאה:", out.getvalue())
🔧 רוצים יותר שליטה?
הנה עוד אפשרויות שימושיות:
💬 לכידת stderr
@contextmanager
def capture_stderr():
old = sys.stderr
sys.stderr = buffer = io.StringIO()
try:
yield buffer
finally:
sys.stderr = old
🔁 לכידת stdout
+ stderr
משולבים
@contextmanager
def capture_output():
old_stdout = sys.stdout
old_stderr = sys.stderr
sys.stdout = sys.stderr = buffer = io.StringIO()
try:
yield buffer
finally:
sys.stdout = old_stdout
sys.stderr = old_stderr
💡 דוגמאות מהחיים האמיתיים
✅ בדיקת הפלט של פונקציה
def say_hello(name):
print(f"Hello, {name}!")
with capture_stdout() as out:
say_hello("Pythonista")
assert "Hello, Pythonista!" in out.getvalue()
🔕 השתקת פלט "רועש"
with capture_stdout():
import noisy_library
📝 רישום לוג של פלט מפקודה חיצונית
with capture_output() as out:
run_some_cli_tool()
with open("cli_output.log", "w") as f:
f.write(out.getvalue())
🔀 ומה אם צריך גם לראות וגם ללכוד?
לפעמים רוצים שהפלט של print()
גם יוצג בטרמינל וגם יישמר. אפשר לעשות זאת באמצעות אובייקט Tee
:
class Tee(io.StringIO):
def __init__(self, original):
super().__init__()
self.original = original
def write(self, text):
self.original.write(text)
super().write(text)
@contextmanager
def capture_stdout_tee():
old_stdout = sys.stdout
sys.stdout = tee = Tee(old_stdout)
try:
yield tee
finally:
sys.stdout = old_stdout
דוגמה:
with capture_stdout_tee() as out:
print("הפלט הזה נראה גם בטרמינל וגם נשמר בבאפר")
print("מהבאפר:", out.getvalue())
נאגד את כל הרעיונות שתוארו לעיל לכדי כלי עזר שימושי ועצמאי ללכידת פלט בפייתון, שניתן:
- לייבא לכל פרויקט,
- להשתמש בו לבדיקות, רישום לוגים וניפוי שגיאות,
- להרחיב בקלות.
📦 קובץ: stdout_capture.py
"""
stdout_capture.py
כלי עזר ללכידת stdout ו-stderr באמצעות מנהלי הקשר.
תומך ב:
- לכידת stdout;
- לכידת stderr;
- לכידת stdout + stderr משולבים;
- מצב "Tee" – פלט בו-זמני לטרמינל ולבאפר.
אינו דורש ספריות חיצוניות.
"""
import sys
import io
from contextlib import contextmanager
@contextmanager
def capture_stdout():
"""
לוכד את stdout (הפלט של print).
"""
old_stdout = sys.stdout
sys.stdout = buffer = io.StringIO()
try:
yield buffer
finally:
sys.stdout = old_stdout
@contextmanager
def capture_stderr():
"""
לוכד את stderr (שגיאות וחריגות).
"""
old_stderr = sys.stderr
sys.stderr = buffer = io.StringIO()
try:
yield buffer
finally:
sys.stderr = old_stderr
@contextmanager
def capture_output():
"""
לוכד את stdout ו-stderr בו-זמנית.
"""
old_stdout = sys.stdout
old_stderr = sys.stderr
sys.stdout = sys.stderr = buffer = io.StringIO()
try:
yield buffer
finally:
sys.stdout = old_stdout
sys.stderr = old_stderr
class Tee(io.StringIO):
"""
מחלקת Tee: שומרת את הפלט ומעבירה אותו ל-stdout/stderr המקורי.
"""
def __init__(self, original):
super().__init__()
self.original = original
def write(self, text):
self.original.write(text)
super().write(text)
def flush(self):
self.original.flush()
@contextmanager
def capture_stdout_tee():
"""
לכידת Tee של stdout – שומר ומציג בו-זמנית.
"""
old_stdout = sys.stdout
sys.stdout = tee = Tee(old_stdout)
try:
yield tee
finally:
sys.stdout = old_stdout
@contextmanager
def capture_output_tee():
"""
לכידת Tee של stdout ו-stderr – שומר ומציג בו-זמנית.
"""
old_stdout = sys.stdout
old_stderr = sys.stderr
# כשיש Tee משולב, חשוב להעביר לו את ה-stdout המקורי כדי שהוא יכתוב למסך,
# ולא ליצור שרשרת של Tee אם משתמשים ב-Tee גם ל-stderr בנפרד.
# כאן, אנחנו רוצים שגם stdout וגם stderr ינותבו לאותו אובייקט Tee,
# והוא ידפיס ל-stdout המקורי.
sys.stdout = sys.stderr = tee = Tee(old_stdout)
try:
yield tee
finally:
sys.stdout = old_stdout
sys.stderr = old_stderr
✅ דוגמאות שימוש
from stdout_capture import capture_stdout, capture_output, capture_stdout_tee
def test_func():
print("Hello from function")
# לכידה פשוטה
with capture_stdout() as out:
test_func()
print("נלכד:", out.getvalue())
# stdout + stderr משולבים
with capture_output() as out:
print("Something")
try:
raise Exception("Oops") # ילכד גם כן
except Exception:
sys.stderr.write("Oops from stderr\n") # הדגמה לכתיבה ל-stderr
# שמירת הפלט והצגתו בו-זמנית
with capture_stdout_tee() as out:
print("Visible AND captured")
print("נלכד ב-Tee:", out.getvalue())