هل يمكنني إعادة توجيه stdout في بيثون إلى نوع من المخزن المؤقت للسلسلة؟

StackOverflow https://stackoverflow.com/questions/1218933

سؤال

أنا أستخدم بيثون ftplib لكتابة عميل FTP صغير، لكن بعض الوظائف الموجودة في الحزمة لا تُرجع مخرجات السلسلة، بل تطبع إليها stdout.أريد إعادة التوجيه stdout إلى كائن سأكون قادرًا على قراءة الإخراج منه.

أنا أعرف stdout يمكن إعادة توجيهه إلى أي ملف عادي باستخدام:

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

لكنني أفضل الطريقة التي لا تستخدم محرك الأقراص المحلي.

أنا أبحث عن شيء مثل BufferedReader في Java والتي يمكن استخدامها لالتفاف المخزن المؤقت في الدفق.

هل كانت مفيدة؟

المحلول

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()

نصائح أخرى

وهناك contextlib.redirect_stdout () وظيفة في بيثون 3.4:

import io
from contextlib import redirect_stdout

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

إليك رمز المثال الذي يوضح كيفية تطبيق ذلك على كبار السن الإصدارات بيثون .

فقط للإضافة إلى إجابة نيد أعلاه:يمكنك استخدام هذا لإعادة توجيه الإخراج إلى أي كائن يطبق طريقة الكتابة (str)..

يمكن استخدام هذا لتحقيق تأثير جيد "لالتقاط" إخراج stdout في تطبيق واجهة المستخدم الرسومية.

إليك مثالًا سخيفًا في 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 !"

بدءًا من Python 2.6، يمكنك استخدام أي شيء ينفذ TextIOBase واجهة برمجة التطبيقات من وحدة io كبديل.يمكّنك هذا الحل أيضًا من الاستخدام sys.stdout.buffer.write() في Python 3 لكتابة سلاسل البايت المشفرة (بالفعل) إلى stdout (انظر stdout في بيثون 3).استخدام StringIO لن تعمل بعد ذلك، لأنه لا sys.stdout.encoding ولا sys.stdout.buffer سيكون متاحا.

الحل باستخدام 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

يعمل هذا الحل مع Python 2 >= 2.6 وPython 3.

يرجى ملاحظة أن جديدنا sys.stdout.write() يقبل فقط سلاسل Unicode و sys.stdout.buffer.write() يقبل فقط سلاسل البايت.قد لا يكون هذا هو الحال بالنسبة للتعليمات البرمجية القديمة، ولكن غالبًا ما يكون هذا هو الحال بالنسبة للتعليمات البرمجية التي تم تصميمها للتشغيل على Python 2 و3 بدون تغييرات، والتي غالبًا ما تستخدم مرة أخرى sys.stdout.buffer.

يمكنك إنشاء تباين طفيف يقبل سلاسل Unicode وbyte لـ 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)

لا يتعين عليك تعيين ترميز المخزن المؤقت على sys.stdout.encoding، ولكن هذا يساعد عند استخدام هذه الطريقة لاختبار/مقارنة مخرجات البرنامج النصي.

تعمل هذه الطريقة على استعادة sys.stdout حتى لو كان هناك استثناء.كما أنه يحصل على أي إخراج قبل الاستثناء.

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

تم اختباره في Python 2.7.10 باستخدام io.BytesIO()

تم الاختبار في Python 3.6.4 باستخدام io.StringIO()


تمت إضافة بوب لحالة إذا شعرت أن أي شيء من تجربة التعليمات البرمجية المعدلة/الموسعة قد يصبح مثيرًا للاهتمام بأي حال من الأحوال، وإلا لا تتردد في حذفها

إعلان إعلامي...بعض الملاحظات من التجارب الموسعة أثناء العثور على بعض الآليات القابلة للتطبيق "للحصول على" المخرجات، من إخراج numexpr.print_versions() مباشرة إلى <stdout> (عند الحاجة إلى تنظيف واجهة المستخدم الرسومية وجمع التفاصيل في تقرير تصحيح الأخطاء)

# 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
'''

في Python3.6، فقد ولت وحدات StringIO وcStringIO، يجب عليك استخدام io.StringIO instead.So يجب عليك القيام بذلك مثل الجواب الأول:

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()

استخدم pipe() والكتابة إلى واصف الملف المناسب.

https://docs.python.org/library/os أتش تي أم أل # ملف واصف-عمليات

وقال مدير سياق 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()

واستخدام مثل هذا:

>>> with RedirectedStdout() as out:
>>>     print('asdf')
>>>     s = str(out)
>>>     print('bsdf')
>>> print(s, out)
'asdf\n' 'asdf\nbsdf\n'
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top