কোনও স্ক্রিপ্ট থেকে স্টাটআউট ক্যাপচার করবেন?


94

ধরুন এখানে কোনও স্ক্রিপ্ট এরকম কিছু করছে:

# module writer.py
import sys

def write():
    sys.stdout.write("foobar")

এখন ধরুন আমি writeফাংশনটির আউটপুট ক্যাপচার করতে এবং এটি আরও প্রক্রিয়াকরণের জন্য একটি ভেরিয়েবলে সঞ্চয় করতে চাই। নিষ্পাপ সমাধানটি ছিল:

# module mymodule.py
from writer import write

out = write()
print out.upper()

তবে এটি কাজ করে না। আমি অন্য একটি সমাধান নিয়ে এসেছি এবং এটি কাজ করে, তবে দয়া করে সমস্যাটি সমাধানের আরও ভাল উপায় আছে কিনা তা আমাকে জানান। ধন্যবাদ

import sys
from cStringIO import StringIO

# setup the environment
backup = sys.stdout

# ####
sys.stdout = StringIO()     # capture output
write()
out = sys.stdout.getvalue() # release output
# ####

sys.stdout.close()  # close the stream 
sys.stdout = backup # restore original stdout

print out.upper()   # post processing

উত্তর:


51

সেটিংস stdoutএটি করার একটি যুক্তিসঙ্গত উপায়। আরেকটি হ'ল এটি অন্য প্রক্রিয়া হিসাবে চালানো:

import subprocess

proc = subprocess.Popen(["python", "-c", "import writer; writer.write()"], stdout=subprocess.PIPE)
out = proc.communicate()[0]
print out.upper()

4
চেক_আউটপুট সরাসরি একটি উপ-প্রসেসে চালিত কমান্ডের আউটপুটকে ক্যাপচার করে: <br> মান = সাবপ্রসেসকসিচ_আউটপুট (কমান্ড, শেল = ট্রু)
আর্থার

4
ফর্ম্যাট সংস্করণ :value = subprocess.check_output(command, shell=True)
নায়ে

51

এখানে আপনার কোডের একটি প্রসঙ্গ পরিচালক রয়েছে। এটি দুটি মানের একটি তালিকা দেয়; প্রথমটি স্টাডাউট, দ্বিতীয়টি স্টার্ডার।

import contextlib
@contextlib.contextmanager
def capture():
    import sys
    from cStringIO import StringIO
    oldout,olderr = sys.stdout, sys.stderr
    try:
        out=[StringIO(), StringIO()]
        sys.stdout,sys.stderr = out
        yield out
    finally:
        sys.stdout,sys.stderr = oldout, olderr
        out[0] = out[0].getvalue()
        out[1] = out[1].getvalue()

with capture() as out:
    print 'hi'

এই সমাধান ভালবাসা। আমি সংশোধন করেছি, যাতে দুর্ঘটনাবশত এমন স্ট্রিমটি হারাতে না পারে যার উপর আমি আউটপুট আশা করি না, যেমন অপ্রত্যাশিত ত্রুটি। আমার ক্ষেত্রে ক্যাপচার () sys.stderr বা sys.stdout কে প্যারামিটার হিসাবে গ্রহণ করতে পারে, কেবলমাত্র সেই স্ট্রিমটি ক্যাপচার করার ইঙ্গিত দেয়।
জোশুয়া রিচার্ডসন

: StringIO কোনো ফ্যাশন ইউনিকোড সমর্থন করে না, তাই আপনি উপরে সমর্থন নন- ASCII অক্ষর করতে এখানে উত্তর সংহত করতে পারেন stackoverflow.com/a/1819009/425050
mafrosis

4
পরিশেষে একটি উপার্জিত মান পরিবর্তন করা সত্যই বরং জঞ্জাল - এর সাথে with capture() as out:আলাদা আচরণ করবেwith capture() as out, err:
এরিক

4
ইউনিকোড / stdout.buffer সমর্থন আইও মডিউল ব্যবহার করে পৌঁছে যেতে পারে। আমার উত্তর দেখুন ।
জনিজেডি

4
আপনি যদি subprocesssys.stdout / stderr এ আউটপুট পুনর্নির্দেশ করেন তবে এই দ্রবণটি ভেঙে যায়। এটি কারণ StringIOকোনও আসল ফাইল অবজেক্ট নয় এবং fileno()ফাংশনটি মিস করে ।
letmaik

47

ভবিষ্যতের দর্শনার্থীদের জন্য: পাইথন ৩.৪ প্রসঙ্গ লিবিবটিredirect_stdout প্রাসঙ্গিক ব্যবস্থাপকের মাধ্যমে সরাসরি এটি ( পাইথন প্রসঙ্গে লিখিত সহায়তা দেখুন ) সরবরাহ করে:

from contextlib import redirect_stdout
import io

f = io.StringIO()
with redirect_stdout(f):
    help(pow)
s = f.getvalue()

4
Sys.stdout.buffer (বাইট লেখার সময় আপনার যেমন করা দরকার) তে লেখার চেষ্টা করার সময় এটি সমস্যার সমাধান করে না। স্ট্রিংআইও-তে বাফার অ্যাট্রিবিউট নেই, অন্যদিকে টেক্সটআইওআরপিআর রয়েছে। @ জনিজেডি থেকে উত্তরটি দেখুন।
ওয়েভার

10

এটি আমার মূল কোডটির সজ্জিত অংশ counter

writer.py একই রয়ে গেছে:

import sys

def write():
    sys.stdout.write("foobar")

mymodule.py তীব্রভাবে পরিবর্তিত হয়:

from writer import write as _write
from decorators import capture

@capture
def write():
    return _write()

out = write()
# out post processing...

এবং এখানে সাজসজ্জা রয়েছে:

def capture(f):
    """
    Decorator to capture standard output
    """
    def captured(*args, **kwargs):
        import sys
        from cStringIO import StringIO

        # setup the environment
        backup = sys.stdout

        try:
            sys.stdout = StringIO()     # capture output
            f(*args, **kwargs)
            out = sys.stdout.getvalue() # release output
        finally:
            sys.stdout.close()  # close the stream 
            sys.stdout = backup # restore original stdout

        return out # captured output wrapped in a string

    return captured

10

অথবা ইতিমধ্যে উপস্থিত কার্যকারিতা ব্যবহার করুন ...

from IPython.utils.capture import capture_output

with capture_output() as c:
    print('some output')

c()

print c.stdout

9

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

পাইথন ২.6 দিয়ে শুরু করে আপনি TextIOBaseএপিআই ব্যবহার করতে পারেন , যার মধ্যে অনুপস্থিত বৈশিষ্ট্যগুলি অন্তর্ভুক্ত রয়েছে:

import sys
from io import TextIOWrapper, BytesIO

# setup the environment
old_stdout = sys.stdout
sys.stdout = TextIOWrapper(BytesIO(), sys.stdout.encoding)

# do some writing (indirectly)
write("blub")

# 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

# do stuff with the output
print(out.upper())

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

Stdout.buffer ব্যবহার না করে সরাসরি স্টডআউটে বাইট স্ট্রিংগুলি প্রেরণকারী কোডকে যদি আপনার সমর্থন করতে হয় তবে আপনি এই প্রকরণটি ব্যবহার করতে পারেন:

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


4

ওএস পর্যায়ে একটি স্ট্রিম পুনঃনির্দেশ করতে এখানে প্রশ্ন (আউটপুটটিকে পুনর্নির্দেশ করার উপায় উদাহরণ নয় tee) os.dup2এটি দুর্দান্ত কারণ এটি আপনার প্রোগ্রাম থেকেও যে আদেশগুলি প্রয়োগ করেছে তা প্রয়োগ করা হবে।


4

আমি মনে করি আপনার এই চারটি বস্তুর দিকে নজর দেওয়া উচিত:

from test.test_support import captured_stdout, captured_output, \
    captured_stderr, captured_stdin

উদাহরণ:

from writer import write

with captured_stdout() as stdout:
    write()
print stdout.getvalue().upper()

ইউপিডি: এরিক যেমন একটি মন্তব্যে বলেছিলেন, তাদের সরাসরি ব্যবহার করা উচিত নয়, তাই আমি এটি অনুলিপি করে আটকালাম।

# Code from test.test_support:
import contextlib
import sys

@contextlib.contextmanager
def captured_output(stream_name):
    """Return a context manager used by captured_stdout and captured_stdin
    that temporarily replaces the sys stream *stream_name* with a StringIO."""
    import StringIO
    orig_stdout = getattr(sys, stream_name)
    setattr(sys, stream_name, StringIO.StringIO())
    try:
        yield getattr(sys, stream_name)
    finally:
        setattr(sys, stream_name, orig_stdout)

def captured_stdout():
    """Capture the output of sys.stdout:

       with captured_stdout() as s:
           print "hello"
       self.assertEqual(s.getvalue(), "hello")
    """
    return captured_output("stdout")

def captured_stderr():
    return captured_output("stderr")

def captured_stdin():
    return captured_output("stdin")

4

আমি প্রাসঙ্গিক ব্যবস্থাপনার সমাধানটি পছন্দ করি তবে আপনার যদি ওপেন ফাইল এবং ফাইলনো সমর্থন সহ সঞ্চিত বাফার প্রয়োজন হয় তবে আপনি এই জাতীয় কিছু করতে পারেন।

import six
from six.moves import StringIO


class FileWriteStore(object):
    def __init__(self, file_):
        self.__file__ = file_
        self.__buff__ = StringIO()

    def __getattribute__(self, name):
        if name in {
            "write", "writelines", "get_file_value", "__file__",
                "__buff__"}:
            return super(FileWriteStore, self).__getattribute__(name)
        return self.__file__.__getattribute__(name)

    def write(self, text):
        if isinstance(text, six.string_types):
            try:
                self.__buff__.write(text)
            except:
                pass
        self.__file__.write(text)

    def writelines(self, lines):
        try:
            self.__buff__.writelines(lines)
        except:
            pass
        self.__file__.writelines(lines)

    def get_file_value(self):
        return self.__buff__.getvalue()

ব্যবহার

import sys
sys.stdout = FileWriteStore(sys.stdout)
print "test"
buffer = sys.stdout.get_file_value()
# you don't want to print the buffer while still storing
# else it will double in size every print
sys.stdout = sys.stdout.__file__
print buffer

2

এখানে আরও একটি সরলকরণের জন্য সিএসের ডেন্ডার-আইও রেফার্নিসের সুবিধা গ্রহণের জন্য @ জনিজেডি-র উত্তর সমর্থনকারী লেখার বাইটস থেকে অনুমানের অনুপ্রেরণা নিচ্ছেন এমন একটি প্রসঙ্গ পরিচালক এখানে আছেন ।buffer

import io
import sys
import contextlib


@contextlib.contextmanager
def capture_output():
    output = {}
    try:
        # Redirect
        sys.stdout = io.TextIOWrapper(io.BytesIO(), sys.stdout.encoding)
        sys.stderr = io.TextIOWrapper(io.BytesIO(), sys.stderr.encoding)
        yield output
    finally:
        # Read
        sys.stdout.seek(0)
        sys.stderr.seek(0)
        output['stdout'] = sys.stdout.read()
        output['stderr'] = sys.stderr.read()
        sys.stdout.close()
        sys.stderr.close()

        # Restore
        sys.stdout = sys.__stdout__
        sys.stderr = sys.__stderr__


with capture_output() as output:
    print('foo')
    sys.stderr.buffer.write(b'bar')

print('stdout: {stdout}'.format(stdout=output['stdout']))
print('stderr: {stderr}'.format(stderr=output['stderr']))

আউটপুট হল:

stdout: foo

stderr: bar
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.