পাইথন ফাংশন কল থেকে স্টডআউট আউটপুট কীভাবে ক্যাপচার করবেন?


112

আমি পাইথন লাইব্রেরি ব্যবহার করছি যা কোনও বস্তুর জন্য কিছু করে

do_something(my_object)

এবং এটি পরিবর্তন। এটি করার সময় এটি স্ট্যাডআউটের জন্য কিছু পরিসংখ্যান মুদ্রণ করে এবং আমি এই তথ্যের উপর একটি খপ্পর পেতে চাই। যথাযথ সমাধানটি do_something()সম্পর্কিত তথ্য ফেরত দেওয়ার জন্য পরিবর্তন করা হবে ,

out = do_something(my_object)

তবে do_something()এই ইস্যুটি নিয়ে যাওয়ার আগে কিছুটা সময় হয়ে যাবে । একটি workaround হিসাবে, আমি do_something()stdout লিখুন যাই হোক না কেন পার্সিং সম্পর্কে চিন্তা ।

কোডে দুটি পয়েন্টের মধ্যে আমি কীভাবে স্টডআউট আউটপুট ক্যাপচার করব?

start_capturing()
do_something(my_object)
out = end_capturing()

?



লিঙ্কযুক্ত প্রশ্নের আমার উত্তরটি এখানেও প্রযোজ্য।
মার্টিজন পিটারস

আমি যে একবার এবং সর্বোত্তম উত্তর আমি খুঁজে পাওয়া যায় তাহাই চেষ্টা: stackoverflow.com/a/3113913/1330293
elyase

@ ইলিজ লিঙ্ক করা উত্তরটি একটি মার্জিত সমাধান
পাইক্লার

এই উত্তর দেখুন ।
মার্টিনিউ

উত্তর:


183

এই প্রসঙ্গে পরিচালক ব্যবহার করে দেখুন:

from io import StringIO 
import sys

class Capturing(list):
    def __enter__(self):
        self._stdout = sys.stdout
        sys.stdout = self._stringio = StringIO()
        return self
    def __exit__(self, *args):
        self.extend(self._stringio.getvalue().splitlines())
        del self._stringio    # free up some memory
        sys.stdout = self._stdout

ব্যবহার:

with Capturing() as output:
    do_something(my_object)

output এখন ফাংশন কল দ্বারা মুদ্রিত লাইন ধারণকারী একটি তালিকা।

উন্নত ব্যবহার:

যা স্পষ্ট না হতে পারে তা হ'ল এটি একাধিক বার করা যেতে পারে এবং ফলাফলগুলি সম্মতিযুক্ত:

with Capturing() as output:
    print('hello world')

print('displays on screen')

with Capturing(output) as output:  # note the constructor argument
    print('hello world2')

print('done')
print('output:', output)

আউটপুট:

displays on screen                     
done                                   
output: ['hello world', 'hello world2']

আপডেট : সেগুলিকে যোগ redirect_stdout()করতে contextlib(সহ পাইথন 3.4 মধ্যে redirect_stderr())। সুতরাং আপনি এটির io.StringIOসাথে একই জাতীয় ফলাফল অর্জন করতে পারেন (যদিও Capturingতালিকাগুলির পাশাপাশি প্রসঙ্গ ব্যবস্থাপক হিসাবে যুক্তিযুক্তভাবে আরও সুবিধাজনক)।


ধন্যবাদ! এবং উন্নত বিভাগটি যুক্ত করার জন্য ধন্যবাদ ... আমি প্রথমে তালিকায় বন্দী লেখাটি আটকে রাখার জন্য একটি স্লাইস অ্যাসাইনমেন্ট ব্যবহার করেছি, তারপরে আমি নিজেকে মাথায় kedোকালাম এবং .extend()পরিবর্তে ব্যবহার করেছি যাতে আপনি লক্ষ্য করেছেন ঠিক তেমনই এটি যুক্তিযুক্তভাবে ব্যবহার করা যেতে পারে। :-)
কিন্ডেল করুন

পিএস যদি এটি বারবার ব্যবহৃত হতে থাকে, তবে আমি সদস্যটির দ্বারা ধারণকৃত কিছু স্মৃতি ছেড়ে দেওয়ার জন্য পদ্ধতিতে কল করার self._stringio.truncate(0)পরে একটি যুক্ত করার পরামর্শ দেব । self.extend()__exit__()_stringio
মার্টিনিউ

25
দুর্দান্ত উত্তর, ধন্যবাদ। পাইথন 3 এর জন্য, from io import StringIOপ্রসঙ্গ ম্যানেজারে প্রথম লাইনের পরিবর্তে ব্যবহার করুন।
ওয়াটওয়ার

1
এই থ্রেড-নিরাপদ? যদি কোনও কিছু থ্রেড / কল প্রিন্ট () ব্যবহার করে তবে কী ঘটে?
দারিয়েরিস্ট

1
এই উত্তর সি ভাগ করা লাইব্রেরি থেকে আউটপুট জন্য কাজ করবে না, পরিবর্তে এই উত্তর দেখুন ।
ক্রাইমিকেল

81

অজগর> = 3.4 এ, প্রসঙ্গ লিবে একটি redirect_stdoutসাজসজ্জা রয়েছে । এটি আপনার প্রশ্নের উত্তরটির মতো ব্যবহার করা যেতে পারে:

import io
from contextlib import redirect_stdout

f = io.StringIO()
with redirect_stdout(f):
    do_something(my_object)
out = f.getvalue()

ডক্স থেকে :

অস্থায়ীভাবে sys.stdout অন্য কোনও ফাইল বা ফাইলের মতো অবজেক্টে পুনঃনির্দেশের জন্য প্রসঙ্গ পরিচালক।

এই সরঞ্জামটি বিদ্যমান ফাংশনগুলিতে বা ক্লাসগুলিতে নমনীয়তা যুক্ত করে যার আউটপুট স্টাডাউটের জন্য কঠোর হয়।

উদাহরণস্বরূপ, সহায়তার আউটপুট () সাধারণত sys.stdout এ প্রেরণ করা হয়। আপনি আউটপুটটিকে একটি আইও স্ট্রিংআইও অবজেক্টে পুনর্নির্দেশের মাধ্যমে স্ট্রিংয়ে আউটপুট ক্যাপচার করতে পারেন:

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

সাহায্যের আউটপুট ডিস্কের কোনও ফাইলে প্রেরণ করতে, আউটপুটটিকে একটি নিয়মিত ফাইলে পুনর্নির্দেশ করুন:

 with open('help.txt', 'w') as f:
     with redirect_stdout(f):
         help(pow)

Sys.stderr এ সাহায্যের আউটপুট প্রেরণ করতে:

with redirect_stdout(sys.stderr):
    help(pow)

নোট করুন যে sys.stdout- এ বিশ্বব্যাপী পার্শ্ব প্রতিক্রিয়াটির অর্থ এই প্রসঙ্গ পরিচালকটি লাইব্রেরি কোড এবং সর্বাধিক থ্রেডযুক্ত অ্যাপ্লিকেশনগুলিতে ব্যবহারের জন্য উপযুক্ত নয়। উপ-প্রক্রিয়াগুলির আউটপুট নেওয়ার ক্ষেত্রেও এর কোনও প্রভাব নেই। তবে এটি এখনও অনেক ইউটিলিটি স্ক্রিপ্টগুলির জন্য একটি দরকারী পন্থা।

এই প্রসঙ্গে পরিচালক পুনরায় প্রেরণকারী rant


যখন চেষ্টা করা f = io.StringIO() with redirect_stdout(f): logger = getLogger('test_logger') logger.debug('Test debug message') out = f.getvalue() self.assertEqual(out, 'DEBUG:test_logger:Test debug message')। এটি আমাকে একটি ত্রুটি দেয়:AssertionError: '' != 'Test debug message'
ইজিজ দুর্দিয়েভ

যার অর্থ আমি কিছু ভুল করেছি বা এটি স্টডআউট লগটি ধরতে পারেনি।
ইজিজ দূর্দিয়েভ

@ এজিজডুরডিয়েভ, logger.debugডিফল্টরূপে স্টডআউটকে লিখবেন না। আপনি যদি আপনার লগ কলটি প্রতিস্থাপন করেন print()তবে বার্তাটি দেখতে হবে।
ForeverWintr

হ্যাঁ, আমি জানি, কিন্তু আমি কি তাই মত stdout- এ লিখতে করুন: stream_handler = logging.StreamHandler(sys.stdout)। এবং সেই হ্যান্ডলারটি আমার লগারে যুক্ত করুন। সুতরাং এটি stdout লিখতে হবে এবং redirect_stdoutএটি ধরা উচিত, তাই না?
ইজিজ দুরদীয়েভ

আমার সন্দেহ হয় যে সমস্যাটি আপনি আপনার লগারটি কনফিগার করেছেন সেভাবেই। আমি যাচাই করব যে এটি redirect_stdout ছাড়াই stdout প্রিন্ট করে। যদি এটি হয় তবে প্রসঙ্গ পরিচালকটি প্রস্থান না করা পর্যন্ত সম্ভবত বাফারটি ফ্লাশ করা হবে না।
ForeverWintr

0

ফাইল পাইপ ব্যবহার করে এখানে একটি অ্যাসিঙ্ক সমাধান রয়েছে।

import threading
import sys
import os

class Capturing():
    def __init__(self):
        self._stdout = None
        self._stderr = None
        self._r = None
        self._w = None
        self._thread = None
        self._on_readline_cb = None

    def _handler(self):
        while not self._w.closed:
            try:
                while True:
                    line = self._r.readline()
                    if len(line) == 0: break
                    if self._on_readline_cb: self._on_readline_cb(line)
            except:
                break

    def print(self, s, end=""):
        print(s, file=self._stdout, end=end)

    def on_readline(self, callback):
        self._on_readline_cb = callback

    def start(self):
        self._stdout = sys.stdout
        self._stderr = sys.stderr
        r, w = os.pipe()
        r, w = os.fdopen(r, 'r'), os.fdopen(w, 'w', 1)
        self._r = r
        self._w = w
        sys.stdout = self._w
        sys.stderr = self._w
        self._thread = threading.Thread(target=self._handler)
        self._thread.start()

    def stop(self):
        self._w.close()
        if self._thread: self._thread.join()
        self._r.close()
        sys.stdout = self._stdout
        sys.stderr = self._stderr

ব্যবহারের উদাহরণ:

from Capturing import *
import time

capturing = Capturing()

def on_read(line):
    # do something with the line
    capturing.print("got line: "+line)

capturing.on_readline(on_read)
capturing.start()
print("hello 1")
time.sleep(1)
print("hello 2")
time.sleep(1)
print("hello 3")
capturing.stop()
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.