{"id":3016,"date":"2025-09-21T05:09:44","date_gmt":"2025-09-21T03:09:44","guid":{"rendered":"https:\/\/davidka.net\/ru\/?p=3016"},"modified":"2025-09-22T02:05:12","modified_gmt":"2025-09-22T00:05:12","slug":"capturing-stdout-without-external-libraries","status":"publish","type":"post","link":"https:\/\/de.davidka.net\/de\/2025\/09\/21\/capturing-stdout-without-external-libraries\/","title":{"rendered":"\ud83e\uddf2 Wie man print() in Python \u201eabf\u00e4ngt\u201d: stdout ohne externe Bibliotheken abfangen"},"content":{"rendered":"\n<p class=\"has-neve-link-color-color has-text-color has-link-color has-medium-font-size wp-elements-d7bf8d9e111b1ccdba68cda0dffbb5b7 wp-block-paragraph\">In Python kann man das, was \u00fcber <code class=\"\" data-line=\"\">print()<\/code> auf dem Bildschirm ausgegeben wird, abfangen.<br>Dies ist n\u00fctzlich f\u00fcr <strong>Tests<\/strong>, <strong>Debugging<\/strong>, <strong>Logging<\/strong> oder um \u201elaute\u201d Ausgaben zu unterdr\u00fccken.<br>Ich zeige, wie man dies elegant macht \u2014 nur mit der <strong>Standardbibliothek<\/strong> und wenigen Codezeilen.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83e\udde9 Verst\u00e4ndnis von Context Managern in Python<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Was ist ein Context Manager?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Ein <strong>Context Manager<\/strong> verwaltet Ressourcen sicher und organisiert.<br>Er definiert das Verhalten bei <strong>Initialisierung<\/strong> und <strong>Aufr\u00e4umen<\/strong> rund um einen Codeblock.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Beispiel: Arbeiten mit Dateien<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">with open(&quot;file.txt&quot;, &quot;w&quot;) as f:\n    f.write(&quot;Hallo, Welt!&quot;)\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">\u2705 Automatisches Aufr\u00e4umen: Die Datei wird geschlossen, selbst wenn eine Ausnahme auftritt.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">Warum Context Manager n\u00fctzlich sind<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Automatisches Aufr\u00e4umen<\/strong> \u2013 Ressourcen werden automatisch freigegeben<\/li>\n\n\n\n<li><strong>Sicherheit bei Fehlern<\/strong> \u2013 Aufr\u00e4umen erfolgt auch bei Ausnahmen<\/li>\n\n\n\n<li><strong>Code-Lesbarkeit<\/strong> \u2013 Setup\/Teardown-Logik an einer Stelle<\/li>\n\n\n\n<li><strong>Wiederverwendbarkeit<\/strong> \u2013 geeignet f\u00fcr Dateien, Locks, Netzwerkverbindungen oder stdout<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">Nutzung von <code class=\"\" data-line=\"\">@contextmanager<\/code> aus <code class=\"\" data-line=\"\">contextlib<\/code><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Der Dekorator <code class=\"\" data-line=\"\">@contextmanager<\/code> erlaubt das Erstellen von Context Managern mittels <strong>Generatoren<\/strong>:<\/p>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">from contextlib import contextmanager\n\n@contextmanager\ndef my_context():\n    print(&quot;Wir betreten den Kontext&quot;)\n    resource = &quot;eine Ressource&quot;\n    try:\n        yield resource\n    finally:\n        print(&quot;Wir verlassen den Kontext&quot;)\n\nwith my_context() as res:\n    print(&quot;Innerhalb des Kontexts:&quot;, res)\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Ausgabe:<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">Wir betreten den Kontext\nInnerhalb des Kontexts: eine Ressource\nWir verlassen den Kontext\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">\ud83d\udca1 <strong>Erkl\u00e4rung:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Code vor <code class=\"\" data-line=\"\">yield<\/code> \u2192 wird beim Eintritt ausgef\u00fchrt<\/li>\n\n\n\n<li>Wert aus <code class=\"\" data-line=\"\">yield<\/code> \u2192 verf\u00fcgbar als <code class=\"\" data-line=\"\">as res<\/code><\/li>\n\n\n\n<li>Code nach <code class=\"\" data-line=\"\">yield<\/code> \u2192 wird beim Verlassen ausgef\u00fchrt, auch bei Ausnahme<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Ideal f\u00fcr <strong>tempor\u00e4re \u00c4nderungen des globalen Zustands<\/strong>, z.B. beim Abfangen von <code class=\"\" data-line=\"\">stdout<\/code>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\u26a1 Zusammenfassung: Context Manager f\u00fcr stdout\/stderr<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Aufgabe \/ Szenario<\/th><th>Empfohlener Context Manager<\/th><\/tr><\/thead><tbody><tr><td>Nur <code class=\"\" data-line=\"\">print<\/code> abfangen<\/td><td><code class=\"\" data-line=\"\">capture_stdout<\/code><\/td><\/tr><tr><td>Nur Fehler \/ Ausnahmen abfangen<\/td><td><code class=\"\" data-line=\"\">capture_stderr<\/code><\/td><\/tr><tr><td>stdout und stderr gleichzeitig abfangen<\/td><td><code class=\"\" data-line=\"\">capture_output<\/code><\/td><\/tr><tr><td>Abfangen und gleichzeitig anzeigen<\/td><td><code class=\"\" data-line=\"\">capture_stdout_tee<\/code> \/ <code class=\"\" data-line=\"\">capture_output_tee<\/code><\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83d\udce6 stdout abfangen<\/h2>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">from contextlib import contextmanager\nimport sys, io\n\n@contextmanager\ndef capture_stdout():\n    old_stdout = sys.stdout\n    sys.stdout = buffer = io.StringIO()\n    try:\n        yield buffer\n    finally:\n        sys.stdout = old_stdout\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Beispiel:<\/p>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">with capture_stdout() as out:\n    print(&quot;Diese Ausgabe wurde abgefangen&quot;)\n\nprint(&quot;Abgefangen:&quot;, out.getvalue())\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83d\udd27 stderr oder beide Streams abfangen<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">stderr abfangen<\/h3>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">@contextmanager\ndef capture_stderr():\n    old_stderr = sys.stderr\n    sys.stderr = buffer = io.StringIO()\n    try:\n        yield buffer\n    finally:\n        sys.stderr = old_stderr\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">stdout + stderr abfangen<\/h3>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">@contextmanager\ndef capture_output():\n    old_stdout = sys.stdout\n    old_stderr = sys.stderr\n    sys.stdout = sys.stderr = buffer = io.StringIO()\n    try:\n        yield buffer\n    finally:\n        sys.stdout = old_stdout\n        sys.stderr = old_stderr\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83d\udd00 Tee-Modus: Abfangen und Anzeigen<\/h2>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">class Tee(io.StringIO):\n    def __init__(self, original):\n        super().__init__()\n        self.original = original\n\n    def write(self, text):\n        self.original.write(text)\n        super().write(text)\n\n    def flush(self):\n        self.original.flush()\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Context Manager:<\/p>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">@contextmanager\ndef capture_stdout_tee():\n    old_stdout = sys.stdout\n    sys.stdout = tee = Tee(old_stdout)\n    try:\n        yield tee\n    finally:\n        sys.stdout = old_stdout\n\n@contextmanager\ndef capture_output_tee():\n    old_stdout = sys.stdout\n    old_stderr = sys.stderr\n    sys.stdout = sys.stderr = tee = Tee(old_stdout)\n    try:\n        yield tee\n    finally:\n        sys.stdout = old_stdout\n        sys.stderr = old_stderr\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Beispiel:<\/p>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">with capture_stdout_tee() as out:\n    print(&quot;Sichtbar und abgefangen&quot;)\n\nprint(&quot;Inhalt Tee:&quot;, out.getvalue())\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83d\udce6 Vollst\u00e4ndige Datei: <code class=\"\" data-line=\"\">stdout_capture.py<\/code><\/h2>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">&quot;&quot;&quot;\nTool zum Abfangen von stdout und stderr mit Context Managern.\nUnterst\u00fctzt:\n- stdout abfangen\n- stderr abfangen\n- kombinierte Abfangung\n- Tee-Modus\n&quot;&quot;&quot;\n\nimport sys, io\nfrom contextlib import contextmanager\n\n@contextmanager\ndef capture_stdout():\n    old_stdout = sys.stdout\n    sys.stdout = buffer = io.StringIO()\n    try: yield buffer\n    finally: sys.stdout = old_stdout\n\n@contextmanager\ndef capture_stderr():\n    old_stderr = sys.stderr\n    sys.stderr = buffer = io.StringIO()\n    try: yield buffer\n    finally: sys.stderr = old_stderr\n\n@contextmanager\ndef capture_output():\n    old_stdout = sys.stdout\n    old_stderr = sys.stderr\n    sys.stdout = sys.stderr = buffer = io.StringIO()\n    try: yield buffer\n    finally:\n        sys.stdout = old_stdout\n        sys.stderr = old_stderr\n\nclass Tee(io.StringIO):\n    def __init__(self, original):\n        super().__init__()\n        self.original = original\n    def write(self, text):\n        self.original.write(text)\n        super().write(text)\n    def flush(self):\n        self.original.flush()\n\n@contextmanager\ndef capture_stdout_tee():\n    old_stdout = sys.stdout\n    sys.stdout = tee = Tee(old_stdout)\n    try: yield tee\n    finally: sys.stdout = old_stdout\n\n@contextmanager\ndef capture_output_tee():\n    old_stdout = sys.stdout\n    old_stderr = sys.stderr\n    sys.stdout = sys.stderr = tee = Tee(old_stdout)\n    try: yield tee\n    finally:\n        sys.stdout = old_stdout\n        sys.stderr = old_stderr\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\u2705 Anwendungsbeispiele<\/h2>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">from stdout_capture import capture_stdout, capture_output, capture_stdout_tee\n\ndef test_func():\n    print(&quot;Hallo aus der Funktion&quot;)\n\n# stdout abfangen\nwith capture_stdout() as out:\n    test_func()\nprint(&quot;stdout abgefangen:&quot;, out.getvalue())\n\n# stdout + stderr abfangen\ntry:\n    with capture_output() as out:\n        print(&quot;Etwas&quot;)\n        raise Exception(&quot;Ups!&quot;)\nexcept Exception:\n    pass\nprint(&quot;Abgefangene Ausgabe:&quot;, out.getvalue())\n\n# Abfangen und gleichzeitig anzeigen\nwith capture_stdout_tee() as out:\n    print(&quot;Sichtbar UND abgefangen&quot;)\nprint(&quot;Tee-Inhalt:&quot;, out.getvalue())\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\u26a0\ufe0f Praktische Tipps und Hinweise<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">1\ufe0f\u20e3 Sehr gro\u00dfe Ausgabe<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code class=\"\" data-line=\"\">io.StringIO<\/code> kann bei gro\u00dfen Datenmengen viel Speicher verbrauchen<\/li>\n\n\n\n<li>Verwenden Sie eine tempor\u00e4re Datei:<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">import sys, tempfile\n\nwith tempfile.TemporaryFile(mode=&#039;w+&#039;) as tmp:\n    old_stdout = sys.stdout\n    sys.stdout = tmp\n    try:\n        print(&quot;Viele Daten...&quot;)\n        tmp.seek(0)\n        captured = tmp.read()\n    finally:\n        sys.stdout = old_stdout\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">2\ufe0f\u20e3 Ausgabe von Subprozessen<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code class=\"\" data-line=\"\">capture_stdout()<\/code> <strong>erfasst keine Ausgabe von externen Prozessen<\/strong><\/li>\n\n\n\n<li>Verwenden Sie <code class=\"\" data-line=\"\">subprocess.PIPE<\/code>:<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code line-numbers\"><code class=\" language-python\" data-line=\"\">import subprocess\nresult = subprocess.run(&#091;&quot;ls&quot;, &quot;-la&quot;], capture_output=True, text=True)\nprint(result.stdout)\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">3\ufe0f\u20e3 Threadsicherheit<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code class=\"\" data-line=\"\">sys.stdout<\/code> und <code class=\"\" data-line=\"\">sys.stderr<\/code> sind global \u2192 vermeiden Sie gleichzeitiges Abfangen in mehreren Threads<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">4\ufe0f\u20e3 Wann Tee verwenden<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Debugging von Funktionen mit Logging<\/li>\n\n\n\n<li>Interaktive CLI-Tools<\/li>\n\n\n\n<li>Integrationstests mit Terminalausgabe<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">5\ufe0f\u20e3 Streams wiederherstellen<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Immer <code class=\"\" data-line=\"\">sys.stdout<\/code>\/<code class=\"\" data-line=\"\">sys.stderr<\/code> in <code class=\"\" data-line=\"\">finally<\/code> zur\u00fccksetzen<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">6\ufe0f\u20e3 Zu tiefe Verschachtelung vermeiden<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Mehrfaches Abfangen kann Ausgaben mischen. Verwenden Sie einen Kontext pro Szenario<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">7\ufe0f\u20e3 Best Practices in Tests<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Unit Tests \u2192 <code class=\"\" data-line=\"\">capture_stdout()<\/code> oder <code class=\"\" data-line=\"\">capture_output()<\/code><\/li>\n\n\n\n<li>Manuelles Debugging \u2192 Tee-Modus<\/li>\n\n\n\n<li>\u00dcberpr\u00fcfen Sie den <strong>Inhalt des Puffers<\/strong>, nicht Nebeneffekte<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>In Python kann man das, was \u00fcber print() auf dem Bildschirm ausgegeben wird, abfangen.<br \/>\nDies ist n\u00fctzlich f\u00fcr Tests, Debugging, Logging oder um \u201elaute\u201d Ausgaben zu unterdr\u00fccken.<br \/>\nIch zeige, wie man dies elegant macht \u2014 nur mit der Standardbibliothek und wenigen Codezeilen.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"neve_meta_sidebar":"","neve_meta_container":"","neve_meta_enable_content_width":"","neve_meta_content_width":0,"neve_meta_title_alignment":"","neve_meta_author_avatar":"","neve_post_elements_order":"","neve_meta_disable_header":"","neve_meta_disable_footer":"","neve_meta_disable_title":"","_themeisle_gutenberg_block_has_review":false,"footnotes":""},"categories":[],"tags":[],"class_list":["post-3016","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/de.davidka.net\/de\/wp-json\/wp\/v2\/posts\/3016","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/de.davidka.net\/de\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/de.davidka.net\/de\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/de.davidka.net\/de\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/de.davidka.net\/de\/wp-json\/wp\/v2\/comments?post=3016"}],"version-history":[{"count":0,"href":"https:\/\/de.davidka.net\/de\/wp-json\/wp\/v2\/posts\/3016\/revisions"}],"wp:attachment":[{"href":"https:\/\/de.davidka.net\/de\/wp-json\/wp\/v2\/media?parent=3016"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/de.davidka.net\/de\/wp-json\/wp\/v2\/categories?post=3016"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/de.davidka.net\/de\/wp-json\/wp\/v2\/tags?post=3016"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}