আমি কি পাইথনের স্টাডাউটকে কোনও ধরণের স্ট্রিং বাফারে পুনর্নির্দেশ করতে পারি?


138

আমি ftplibএকটি ছোট এফটিপি ক্লায়েন্ট লিখতে পাইথন ব্যবহার করছি , তবে প্যাকেজের কিছু ফাংশন স্ট্রিং আউটপুট ফেরায় না, তবে মুদ্রণ করুন stdout। আমি এমন stdoutকোনও জিনিসে পুনর্নির্দেশ করতে চাই যা থেকে আমি আউটপুটটি পড়তে সক্ষম হব।

আমি জানি যে stdoutকোনও নিয়মিত ফাইলে এর সাথে পুনঃনির্দেশ করা যেতে পারে:

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

তবে আমি এমন একটি পদ্ধতি পছন্দ করি যা লোকাল ড্রাইভ ব্যবহার করে না।

আমি BufferedReaderজাভাতে এমন কিছু সন্ধান করছি যা একটি স্ট্রিমে বাফারকে আবৃত করতে ব্যবহৃত হতে পারে।


আমি stdout = open("file", "a")নিজে থেকে কিছুই পুনর্নির্দেশ করবে বলে মনে করি না ।
আলেক্সি

উত্তর:


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

52
+1, আপনাকে stdoutসর্বদা উপলভ্য থাকায় মূল বস্তুর রেফারেন্স রাখার দরকার নেই sys.__stdout__Docs.python.org/library/sys.html#sys.__stdout__ দেখুন ।
আয়মান হৌরিহ

92
ঠিক আছে, এটি একটি আকর্ষণীয় বিতর্ক। পরম আসল স্টাডাউট উপলব্ধ, তবে এটির পরিবর্তে যখন আমি করেছি তেমন স্পষ্টভাবে সংরক্ষণ করা ভাল, যেহেতু অন্য কেউ স্টাডাউট প্রতিস্থাপন করতে পারে এবং যদি আপনি স্টাডআউট ব্যবহার করেন তবে আপনি তাদের প্রতিস্থাপনটি ক্লোবার করতে চাইবেন।
নেড ব্যাচেল্ডার

5
এই অপারেশনটি কি এক থ্রেডে অন্য থ্রেডের আচরণকে পরিবর্তন করবে? মানে কি থ্রেডসেফ?
অনুব্রত পরাশর

6
আমি একটি finally:ব্লকে পুরানো স্টডআউটকে পুনরায় নিয়োগ করার জন্য উচ্চতর পরামর্শ দিচ্ছি , তাই এর মধ্যে যদি কোনও ব্যতিক্রম বেড়ে যায় তবে তাও পুনরায় নিয়োগ দেওয়া হয়। try: bkp = sys.stdout ... ... finally: sys.stdout = bkp
ম্যাথিয়াস কুহন

20
যদি আপনি পাইথন 3 এ এটি ব্যবহার করতে চান তবে সিস্ট্রিংআইওকে আইও দিয়ে প্রতিস্থাপন করুন।
অ্যান্টনি ল্যাবারে

80

নেই 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()

এখানে কোড উদাহরণ যা এটি পুরানো পাইথন সংস্করণগুলিতে কীভাবে এটি প্রয়োগ করতে পারে তা দেখায়


3
এর রয়েছে redirect_stderrসর্বশেষ পাইথন খুব!
সিএমসিডিগ্রাগনকাই

আমি মনে করি এই সমাধানের জন্য চেষ্টা / অবশেষে অবরুদ্ধ করার দরকার নেই।
SNR

35

কেবল উপরের নেডের উত্তর যুক্ত করতে: আপনি এটি কোনও লেখার (স্ট্র) পদ্ধতি প্রয়োগ করে এমন কোনও বস্তুর আউটপুট পুনর্নির্দেশ করতে ব্যবহার করতে পারেন ।

এটি একটি জিইউআই অ্যাপ্লিকেশনটিতে স্টাডআউট আউটপুট "ধরা" ভাল প্রভাবের জন্য ব্যবহার করা যেতে পারে।

পাইকিউটিতে একটি নির্বোধ উদাহরণ এখানে:

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 !"

5
পাইথন 2.6 এবং পাইকিউটি 4 নিয়ে আমার জন্য কাজ করে। ভোটিং ওয়ার্কিং কোড ডাউন করার জন্য অদ্ভুত বলে মনে হচ্ছে যখন কেন এটি কাজ করে না আপনি বলতে পারবেন না!
নিকোলাস লেফবভ্রে

9
ফ্ল্যাশ যোগ করতে ভুলবেন না () খুব!
উইল

6

পাইথন ২.6 দিয়ে শুরু করে আপনি প্রতিস্থাপন হিসাবে আইও মডিউল থেকে TextIOBaseএপিআই প্রয়োগকারী যে কোনও কিছুই ব্যবহার করতে পারেন । এই দ্রবণটি আপনাকে sys.stdout.buffer.write()পাইথন 3 এ স্টাডআউটে এনকোডেড বাইট স্ট্রিংগুলি লিখতে (ইতিমধ্যে পাইথন 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

এই সমাধানটি পাইথন 2> = 2.6 এবং পাইথন 3 এর জন্য কাজ করে।

দয়া করে মনে রাখবেন যে আমাদের নতুন sys.stdout.write()কেবল ইউনিকোড স্ট্রিং গ্রহণ করে এবং sys.stdout.buffer.write()কেবলমাত্র বাইট স্ট্রিং গ্রহণ করে। এই পুরানো কোড কেনার ক্ষেত্রে দেখা নাও হতে পারে, কিন্তু প্রায়ই কোডটি পরিবর্তন ছাড়াই পাইথন 2 এবং 3 চালানোর জন্য, যা আবার প্রায়ই ব্যবহার করে নির্মিত হয় কেনার ক্ষেত্রে দেখা যায় sys.stdout.buffer

আপনি সামান্য প্রকরণটি তৈরি করতে পারেন যা ইউনিকোড এবং বাইট স্ট্রিংগুলি গ্রহণ করে 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 বাফারের এনকোডিং সেট করতে হবে না, তবে স্ক্রিপ্ট আউটপুট পরীক্ষা / তুলনা করার জন্য এই পদ্ধতিটি ব্যবহার করার সময় এটি সহায়তা করে।


এই উত্তরটি আমাকে এইচটিপি'র কোর.পি. সহ ব্যবহারের জন্য পরিবেশগত অবজেক্টের স্টডআউট পরম সেট আপ করার সময় সহায়তা করেছিল।
সুগন্ধি

6

এই পদ্ধতিটি সিস্টেস্ট স্টোরআউট পুনরুদ্ধার করে যদি কোনও ব্যতিক্রম থাকে তবে। এটি ব্যতিক্রমের আগে কোনও আউটপুট পায়।

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

পাইথনে 2.7.10 ব্যবহার করে পরীক্ষিত T io.BytesIO()

পাইথন 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
'''

6

পাইথন 3 এর জন্য একটি প্রসঙ্গ পরিচালক:

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'

4

পাইথন ৩..6-এ StringIOএবং cStringIOমডিউলগুলি চলে গেছে, আপনার io.StringIOপরিবর্তে ব্যবহার করা উচিত o সুতরাং আপনার প্রথম উত্তরের মতো এটি করা উচিত:

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

1
উপরের কোডটি কীভাবে কাজ করে এবং প্রশ্নকারীর অবস্থার তুলনায় এটি কীভাবে উন্নতি হয় তা ব্যাখ্যা করে আপনি নিজের উত্তরের গুণমান উন্নত করতে পারেন।
টুনাইস


1

এখানে এই নিতে আরও একটি। contextlib.redirect_stdoutসঙ্গে io.StringIO()হিসাবে নথিভুক্ত মহান, কিন্তু এটা এখনও প্রতিদিন ব্যবহারের জন্য বাগাড়ম্বরপূর্ণ একটি বিট। সাবক্লাসিং করে কীভাবে এটি ওয়ান-লাইনার করা যায় তা এখানে contextlib.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()  

যেহেতু __enter__ নিজেই ফিরে আসে, আপনার প্রসঙ্গ ব্যবস্থাপক অবজেক্টটি ব্লক প্রস্থান করার পরে উপলব্ধ। অধিকন্তু, __repr__ পদ্ধতির জন্য ধন্যবাদ, প্রসঙ্গ পরিচালকের বস্তুর স্ট্রিং উপস্থাপনা আসলে স্টাডআউট। সুতরাং এখন আপনার আছে,

with capture() as message:
    print('Hello World!')
print(str(message)=='Hello World!\n')  # returns True
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.