2009-08-02 33 views
94

Tôi đang sử dụng số ftplib của python để viết một ứng dụng khách FTP nhỏ, nhưng một số chức năng trong gói không trả lại kết quả chuỗi, nhưng in tới stdout. Tôi muốn chuyển hướng stdout đến một đối tượng mà tôi sẽ có thể đọc đầu ra từ.Tôi có thể chuyển hướng stdout trong python vào một số loại bộ đệm chuỗi không?

Tôi biết stdout thể được chuyển hướng vào bất kỳ tập tin thường xuyên với:

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

Nhưng tôi thích một phương pháp mà không sử dụng các ổ đĩa cục bộ.

Tôi đang tìm một cái gì đó giống như BufferedReader trong Java có thể được sử dụng để bọc bộ đệm vào luồng.

+0

Tôi không nghĩ rằng 'stdout = o bút ("tập tin", "a") 'của chính nó sẽ chuyển hướng bất cứ điều gì. – Alexey

Trả lời

148
from cStringIO import StringIO 
import sys 

old_stdout = sys.stdout 
sys.stdout = mystdout = StringIO() 

# blah blah lots of code ... 

sys.stdout = old_stdout 

# examine mystdout.getvalue() 
+40

+1, bạn không cần phải giữ tham chiếu đến đối tượng 'stdout' ban đầu, vì nó luôn có sẵn tại' sys .__ stdout__'. Xem http://docs.python.org/library/sys.html#sys.__stdout__. –

+71

Vâng, đó là một cuộc tranh luận thú vị. Các stdout ban đầu tuyệt đối có sẵn, nhưng khi thay thế như thế này, tốt hơn là sử dụng một lưu rõ ràng như tôi đã làm, vì ai đó có thể đã thay thế stdout và nếu bạn sử dụng __stdout__, bạn sẽ thay thế chúng. –

+5

hoạt động này trong một luồng có làm thay đổi hành vi của các luồng khác không? Tôi có nghĩa là nó threadsafe? –

34

Chỉ cần để thêm vào câu trả lời của Ned trên: bạn có thể sử dụng để chuyển hướng đầu ra để bất kỳ đối tượng mà thực hiện một phương pháp ghi (str).

Điều này có thể được sử dụng để có hiệu quả tốt để "bắt" đầu ra stdout trong ứng dụng GUI.

Dưới đây là một ví dụ ngớ ngẩn trong 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 !" 
+0

Điều này không hoạt động, nó khóa ứng dụng, nhưng tôi không thể giải thích tại sao. –

+3

Làm việc với tôi với python 2.6 và PyQT4. Có vẻ lạ khi bỏ phiếu bầu làm việc khi bạn không thể nói tại sao nó không hoạt động! –

+5

đừng quên thêm tuôn ra() nữa! – Will

4

Bắt đầu với Python 2.6, bạn có thể sử dụng bất cứ điều gì thực hiện TextIOBase API từ các module io như một sự thay thế. Giải pháp này cũng cho phép bạn sử dụng sys.stdout.buffer.write() trong Python 3 để viết các chuỗi byte được mã hóa (đã) thành stdout (xem stdout in Python 3). Sử dụng StringIO sẽ không hoạt động sau đó, vì không phải sys.stdout.encoding cũng không phải sys.stdout.buffer sẽ khả dụng.

Một giải pháp sử dụng 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 

Giải pháp này làm việc cho Python 2> = 2.6 và Python 3.

Xin lưu ý rằng mới sys.stdout.write() chỉ chấp nhận chuỗi unicode của chúng tôi và sys.stdout.buffer.write() chỉ chấp nhận chuỗi byte. Đây có thể không phải là trường hợp cho mã cũ, nhưng thường là trường hợp mã được xây dựng để chạy trên Python 2 và 3 mà không có thay đổi, điều này thường sử dụng sys.stdout.buffer.

Bạn có thể xây dựng sự thay đổi nhỏ chấp nhận unicode và byte chuỗi cho 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) 

Bạn không cần phải thiết lập mã hóa của đệm sys.stdout.encoding, nhưng điều này sẽ giúp khi sử dụng phương pháp này để kiểm tra/so sánh đầu ra tập lệnh.

+0

Câu trả lời này đã giúp tôi khi thiết lập tham số stdout của đối tượng Môi trường để sử dụng với core.py của Httpie. – fragorl

2

Phương pháp này khôi phục sys.stdout ngay cả khi có ngoại lệ. Nó cũng nhận được bất kỳ đầu ra trước khi ngoại lệ.

real_stdout = sys.stdout 
fake_stdout = io.BytesIO() 
try: 
    sys.stdout = fake_stdout 
    # do what you gotta 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 

tôi chỉ thử nghiệm điều này bằng Python 2.7.10, nhưng io.BytesIO được đồn đại là replacement for StringIO in Python 3.

2

Trong Python3.6, các StringIOcStringIO module đã mất hết, bạn nên sử dụng io.StringIO instead.So bạn nên làm điều này như là câu trả lời đầu tiên:

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

Bạn có thể cải thiện chất lượng câu trả lời của mình bằng cách giải thích cách hoạt động của mã trên và cách cải thiện tình hình của Người hỏi. – toonice

+0

Cảm ơn lời khuyên của bạn. – haofly

0

Một nhà quản lý bối cảnh cho python3:

import sys 
from io import StringIO 


class redirected_stdout: 
    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 

    @property 
    def string(self): 
     return self._string_io.getvalue() 

sử dụng như sau:

>>> with redirected_stdout() as out: 
>>>  print('asdf') 
>>>  s = out.string 
>>>  print('bsdf') 
>>> print(s, out.string) 
'asdf\n' 'asdf\nbsdf\n' 
Các vấn đề liên quan