Saya menggunakan python ftplib
untuk menulis klien FTP kecil, tetapi beberapa fungsi dalam paket tidak mengembalikan output string, tetapi mencetak ke stdout
. Saya ingin mengarahkan stdout
ke objek yang hasilnya akan dapat saya baca.
aku tahu stdout
bisa dialihkan ke file biasa dengan:
stdout = open("file", "a")
Tapi saya lebih suka metode yang tidak menggunakan drive lokal.
Saya mencari sesuatu seperti BufferedReader
di Java yang dapat digunakan untuk membungkus buffer ke dalam aliran.
stdout = open("file", "a")
dengan sendirinya akan mengarahkan apapun.Jawaban:
from cStringIO import StringIO # Python3 use: from io import StringIO import sys old_stdout = sys.stdout sys.stdout = mystdout = StringIO() # blah blah lots of code ... sys.stdout = old_stdout # examine mystdout.getvalue()
sumber
stdout
objek asli , karena selalu tersedia disys.__stdout__
. Lihat docs.python.org/library/sys.html#sys.__stdout__ .finally:
blok, jadi itu juga ditugaskan kembali jika pengecualian meningkat di antaranya.try: bkp = sys.stdout ... ... finally: sys.stdout = bkp
Ada fungsi contextlib.redirect_stdout () di Python 3.4:
import io from contextlib import redirect_stdout with io.StringIO() as buf, redirect_stdout(buf): print('redirected') output = buf.getvalue()
Berikut contoh kode yang menunjukkan cara menerapkannya pada versi Python yang lebih lama .
sumber
redirect_stderr
Python terbaru juga!Hanya untuk menambah jawaban Ned di atas: Anda dapat menggunakan ini untuk mengarahkan output ke objek apa pun yang mengimplementasikan metode write (str) .
Ini dapat digunakan untuk efek yang baik untuk "menangkap" keluaran stdout dalam aplikasi GUI.
Berikut contoh konyol di 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 !"
sumber
Metode ini memulihkan sys.stdout meskipun ada pengecualian. Itu juga mendapat keluaran apa pun sebelum pengecualian.
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
Diuji dengan Python 2.7.10 menggunakan
io.BytesIO()
Diuji dengan Python 3.6.4 menggunakan
io.StringIO()
Bob, ditambahkan untuk kasus jika Anda merasa sesuatu dari eksperimen kode yang dimodifikasi / diperpanjang mungkin menarik dalam arti apa pun, jika tidak silakan hapus
# 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 '''
sumber
Dimulai dengan Python 2.6 Anda dapat menggunakan apa pun yang mengimplementasikan
TextIOBase
API dari modul io sebagai penggantinya. Solusi ini juga memungkinkan Anda menggunakansys.stdout.buffer.write()
Python 3 untuk menulis (sudah) string byte yang dikodekan ke stdout (lihat stdout di Python 3 ). MenggunakanStringIO
tidak akan berhasil saat itu, karena tidaksys.stdout.encoding
jugasys.stdout.buffer
akan tersedia.Solusi menggunakan 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
Solusi ini berfungsi untuk Python 2> = 2.6 dan Python 3.
Harap dicatat bahwa baru kami
sys.stdout.write()
hanya menerima string unicode dansys.stdout.buffer.write()
hanya menerima string byte. Ini mungkin bukan kasus untuk kode lama, tetapi sering kali kasus kode yang dibuat untuk berjalan di Python 2 dan 3 tanpa perubahan, yang lagi-lagi sering menggunakansys.stdout.buffer
.Anda dapat membuat sedikit variasi yang menerima string unicode dan byte untuk
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)
Anda tidak perlu menyetel pengkodean buffer sys.stdout.encoding, tetapi ini membantu saat menggunakan metode ini untuk menguji / membandingkan keluaran skrip.
sumber
Manajer konteks untuk python3:
import sys from io import StringIO class RedirectedStdout: 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 def __str__(self): return self._string_io.getvalue()
gunakan seperti ini:
>>> with RedirectedStdout() as out: >>> print('asdf') >>> s = str(out) >>> print('bsdf') >>> print(s, out) 'asdf\n' 'asdf\nbsdf\n'
sumber
Di Python3.6, modul
StringIO
dancStringIO
sudah tidak ada, Anda harus menggunakan sebagaiio.StringIO
gantinya, jadi Anda harus melakukan ini seperti jawaban pertama: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()
sumber
Menggunakan
pipe()
dan tulis ke deskriptor file yang sesuai.https://docs.python.org/library/os.html#file-descriptor-operations
sumber
Ini pendapat lain tentang ini.
contextlib.redirect_stdout
denganio.StringIO()
seperti yang didokumentasikan itu bagus, tapi masih sedikit bertele-tele untuk penggunaan sehari-hari. Berikut cara membuatnya menjadi satu baris dengan subclassingcontextlib.redirect_stdout
:import sys import io from contextlib import redirect_stdout class capture(redirect_stdout): def __init__(self): self.f = io.StringIO() self._new_target = self.f self._old_targets = [] # verbatim from parent class def __enter__(self): self._old_targets.append(getattr(sys, self._stream)) # verbatim from parent class setattr(sys, self._stream, self._new_target) # verbatim from parent class return self # instead of self._new_target in the parent class def __repr__(self): return self.f.getvalue()
Sejak __enter__ mengembalikan diri, Anda memiliki objek pengelola konteks yang tersedia setelah blok dengan keluar. Selain itu, berkat metode __repr__, representasi string dari objek pengelola konteks sebenarnya adalah stdout. Jadi sekarang kamu punya,
with capture() as message: print('Hello World!') print(str(message)=='Hello World!\n') # returns True
sumber