print and python stream stdout redirect

and - ¿Puedo redirigir el stdout en python a algún tipo de buffer de cadena?



python console message (8)

Comenzando con Python 2.6 puede usar cualquier cosa que implemente la API TextIOBase desde el módulo io como reemplazo. Esta solución también le permite usar sys.stdout.buffer.write() en Python 3 para escribir (ya) cadenas de bytes codificadas en stdout (vea stdout en Python 3 ). Usar StringIO no funcionaría entonces, porque ni sys.stdout.encoding ni sys.stdout.buffer estarían disponibles.

Una solución que usa TextIOWrapper:

import sys from io import TextIOWrapper, BytesIO # setup the environment old_stdout = sys.stdout sys.stdout = TextIOWrapper(BytesIO(), sys.stdout.encoding) # do something that writes to stdout or stdout.buffer # get output sys.stdout.seek(0) # jump to the start out = sys.stdout.read() # read output # restore stdout sys.stdout.close() sys.stdout = old_stdout

Esta solución funciona para Python 2> = 2.6 y Python 3.

Tenga en cuenta que nuestro nuevo sys.stdout.write() solo acepta cadenas de caracteres unicode y sys.stdout.buffer.write() solo acepta cadenas de bytes. Puede que este no sea el caso para el código anterior, pero a menudo es el caso para el código que está diseñado para ejecutarse en Python 2 y 3 sin cambios, que a menudo hace uso de sys.stdout.buffer .

Puede construir una ligera variación que acepte cadenas de bytes y unicode para write() :

class StdoutBuffer(TextIOWrapper): def write(self, string): try: return super(StdoutBuffer, self).write(string) except TypeError: # redirect encoded byte strings directly to buffer return super(StdoutBuffer, self).buffer.write(string)

No es necesario configurar la codificación del búfer en sys.stdout.encoding, pero esto ayuda cuando se utiliza este método para probar / comparar el resultado del script.

Estoy usando ftplib de ftplib para escribir un cliente FTP pequeño, pero algunas de las funciones del paquete no devuelven resultados de cadenas, pero imprimen a stdout . Quiero redirigir stdout a un objeto del que podré leer el resultado.

Sé que stdout puede redirigirse a cualquier archivo normal con:

stdout = open("file", "a")

Pero prefiero un método que no utiliza el disco local.

Estoy buscando algo como el BufferedReader en Java que se puede usar para envolver un buffer en una transmisión.


En Python3.6, los módulos StringIO y cStringIO se han ido, debe usar io.StringIO lugar. Por lo tanto, debe hacer esto como la primera respuesta:

import sys from io import StringIO old_stdout = sys.stdout old_stderr = sys.stderr my_stdout = sys.stdout = StringIO() my_stderr = sys.stderr = StringIO() # blah blah lots of code ... sys.stdout = self.old_stdout sys.stderr = self.old_stderr // if you want to see the value of redirect output, be sure the std output is turn back print(my_stdout.getvalue()) print(my_stderr.getvalue()) my_stdout.close() my_stderr.close()


Este método restaura sys.stdout incluso si hay una excepción. También obtiene cualquier salida antes de la excepción.

import io import sys real_stdout = sys.stdout fake_stdout = io.BytesIO() # or perhaps io.StringIO() try: sys.stdout = fake_stdout # do what you have to do to create some output finally: sys.stdout = real_stdout output_string = fake_stdout.getvalue() fake_stdout.close() # do what you want with the output_string

Probado en Python 2.7.10 usando io.BytesIO()

Probado en Python 3.6.4 usando io.StringIO()

Bob, agregado para un caso si sientes que algo de la experimentación con código modificado / extendido puede ser interesante en cualquier sentido, de lo contrario no dudes en eliminarlo

Ad informandum ... algunas observaciones de la experimentación extendida durante la búsqueda de algunas mecánicas viables para "agarrar" salidas, dirigidas por numexpr.print_versions() directamente a la <stdout> (ante la necesidad de limpiar la GUI y recopilar detalles en el informe de depuración)

# THIS WORKS AS HELL: as Bob Stein proposed years ago: # py2 SURPRISEDaBIT: # import io import sys # real_stdout = sys.stdout # PUSH <stdout> ( store to REAL_ ) fake_stdout = io.BytesIO() # .DEF FAKE_ try: # FUSED .TRY: sys.stdout.flush() # .flush() before sys.stdout = fake_stdout # .SET <stdout> to use FAKE_ # ----------------------------------------- # + do what you gotta do to create some output print 123456789 # + import numexpr # + QuantFX.numexpr.__version__ # + [3] via fake_stdout re-assignment, as was bufferred + "late" deferred .get_value()-read into print, to finally reach -> real_stdout QuantFX.numexpr.print_versions() # + [4] via fake_stdout re-assignment, as was bufferred + "late" deferred .get_value()-read into print, to finally reach -> real_stdout _ = os.system( ''echo os.system() redir-ed'' )# + [1] via real_stdout + "late" deferred .get_value()-read into print, to finally reach -> real_stdout, if not ( _ = )-caught from RET-d "byteswritten" / avoided from being injected int fake_stdout _ = os.write( sys.stderr.fileno(), # + [2] via stderr + "late" deferred .get_value()-read into print, to finally reach -> real_stdout, if not ( _ = )-caught from RET-d "byteswritten" / avoided from being injected int fake_stdout b''os.write() redir-ed'' )# *OTHERWISE, if via fake_stdout, EXC <_io.BytesIO object at 0x02C0BB10> Traceback (most recent call last): # ----------------------------------------- # ? io.UnsupportedOperation: fileno #'''''' ? YET: <_io.BytesIO object at 0x02C0BB10> has a .fileno() method listed #>>> ''fileno'' in dir( sys.stdout ) -> True ? HAS IT ADVERTISED, #>>> pass; sys.stdout.fileno -> <built-in method fileno of _io.BytesIO object at 0x02C0BB10> #>>> pass; sys.stdout.fileno()-> Traceback (most recent call last): # File "<stdin>", line 1, in <module> # io.UnsupportedOperation: fileno # ? BUT REFUSES TO USE IT #'''''' finally: # == FINALLY: sys.stdout.flush() # .flush() before ret''d back REAL_ sys.stdout = real_stdout # .SET <stdout> to use POP''d REAL_ sys.stdout.flush() # .flush() after ret''d back REAL_ out_string = fake_stdout.getvalue() # .GET string from FAKE_ fake_stdout.close() # <FD>.close() # +++++++++++++++++++++++++++++++++++++ # do what you want with the out_string # print "/n{0:}/n{1:}{0:}".format( 60 * "///",# "LATE" deferred print the out_string at the very end reached -> real_stdout out_string # ) '''''' PASS''d::::: ... os.system() redir-ed os.write() redir-ed //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 123456789 ''2.5'' -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= Numexpr version: 2.5 NumPy version: 1.10.4 Python version: 2.7.13 |Anaconda 4.0.0 (32-bit)| (default, May 11 2017, 14:07:41) [MSC v.1500 32 bit (Intel)] AMD/Intel CPU? True VML available? True VML/MKL version: Intel(R) Math Kernel Library Version 11.3.1 Product Build 20151021 for 32-bit applications Number of threads used by default: 4 (out of 4 detected cores) -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// >>> EXC''d ::::: ... os.system() redir-ed //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 123456789 ''2.5'' -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= Numexpr version: 2.5 NumPy version: 1.10.4 Python version: 2.7.13 |Anaconda 4.0.0 (32-bit)| (default, May 11 2017, 14:07:41) [MSC v.1500 32 bit (Intel)] AMD/Intel CPU? True VML available? True VML/MKL version: Intel(R) Math Kernel Library Version 11.3.1 Product Build 20151021 for 32-bit applications Number of threads used by default: 4 (out of 4 detected cores) -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Traceback (most recent call last): File "<stdin>", line 9, in <module> io.UnsupportedOperation: fileno ''''''


Hay función contextlib.redirect_stdout () en Python 3.4:

import io from contextlib import redirect_stdout with io.StringIO() as buf, redirect_stdout(buf): print(''redirected'') output = buf.getvalue()

Aquí hay un ejemplo de código que muestra cómo implementarlo en versiones anteriores de Python .


Solo para agregar a la respuesta anterior de Ned: puede usar esto para redirigir la salida a cualquier objeto que implemente un método write (str) .

Esto se puede usar con buenos resultados para "capturar" la salida stdout en una aplicación GUI.

Aquí hay un ejemplo tonto en PyQt:

import sys from PyQt4 import QtGui class OutputWindow(QtGui.QPlainTextEdit): def write(self, txt): self.appendPlainText(str(txt)) app = QtGui.QApplication(sys.argv) out = OutputWindow() sys.stdout=out out.show() print "hello world !"


Un administrador de contexto para python3:

import sys from io import StringIO class redirected_stdout: def __init__(self): self._stdout = None self._string_io = None def __enter__(self): self._stdout = sys.stdout sys.stdout = self._string_io = StringIO() return self def __exit__(self, type, value, traceback): sys.stdout = self._stdout @property def string(self): return self._string_io.getvalue()

usar de esta manera:

>>> with redirected_stdout() as out: >>> print(''asdf'') >>> s = out.string >>> print(''bsdf'') >>> print(s, out.string) ''asdf/n'' ''asdf/nbsdf/n''



from cStringIO import StringIO import sys old_stdout = sys.stdout sys.stdout = mystdout = StringIO() # blah blah lots of code ... sys.stdout = old_stdout # examine mystdout.getvalue()