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''
Use pipe()
y escriba en el descriptor de archivo apropiado.
https://docs.python.org/library/os.html#file-descriptor-operations
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()