2013-05-15 37 views
59

Tôi đang sử dụng một thư viện Python rằng làm điều gì đó cho một đối tượngLàm thế nào để nắm bắt đầu ra stdout từ một cuộc gọi hàm Python?

do_something(my_object) 

và thay đổi nó. Trong khi làm như vậy, nó in một số số liệu thống kê để stdout, và tôi muốn có được một va li về thông tin này. Các giải pháp thích hợp sẽ được thay đổi do_something() để trả lại thông tin liên quan,

out = do_something(my_object) 

nhưng nó sẽ là một thời gian trước khi các nhà phát triển của do_something() được vấn đề này. Để giải quyết vấn đề này, tôi đã suy nghĩ về việc phân tích cú pháp bất cứ điều gì do_something() ghi vào chế độ stdout.

Làm thế nào tôi có thể nắm bắt đầu ra stdout giữa hai điểm trong các mã, ví dụ,

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

?

+2

có thể trùng lặp của [chụp kết quả dis.dis] (http://stackoverflow.com/questions/12111717/capturing-dis-dis-results) –

+0

Câu trả lời của tôi trong câu hỏi được liên kết cũng áp dụng ở đây. –

+0

tôi đã cố gắng để làm điều đó một lần và câu trả lời tốt nhất mà tôi tìm thấy là: câu trả lời http://stackoverflow.com/a/3113913/1330293 – elyase

Trả lời

115

Cố gắng quản lý bối cảnh này:

from cStringIO 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 

Cách sử dụng:

with Capturing() as output: 
    do_something(my_object) 

output bây giờ là một danh sách có chứa các đường in bằng lời gọi hàm.

nâng cao sử dụng:

gì có thể không rõ ràng là điều này có thể được thực hiện nhiều hơn một lần và kết quả nối:

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 

Output:

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

+1 Đó là kewl, tử tế. – martineau

+0

Cảm ơn! Và cảm ơn vì đã thêm phần nâng cao ... Ban đầu tôi đã sử dụng một phép gán slice để gắn văn bản đã được ghi vào danh sách, sau đó tôi lén vào đầu và sử dụng '.extend()' để nó có thể được sử dụng liên tục, giống như bạn nhận thấy. :-) – kindall

+0

Bạn được chào đón - vui vì bạn không quan tâm đến chỉnh sửa của mình. – martineau

27

Trong python> = 3.4, contextlib chứa một trang trí redirect_stdout. Nó có thể được sử dụng để trả lời câu hỏi của bạn như sau:

import io 
from contextlib import redirect_stdout 

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

Từ the docs:

quản lý Bối cảnh tạm thời chuyển hướng sys.stdout để một file hoặc đối tượng tập tin như thế nào.

Công cụ này bổ sung tính linh hoạt cho các chức năng hoặc lớp hiện có có đầu ra được cứng để ngăn chặn.

Ví dụ: đầu ra của trợ giúp() thường được gửi đến sys.stdout. Bạn có thể ghi lại đầu ra đó trong một chuỗi bằng cách chuyển hướng đầu ra đến một số io.StringIO đối tượng:

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

Để gửi kết quả của sự giúp đỡ() vào một tập tin trên đĩa, chuyển hướng đầu ra để một tập tin thường xuyên:

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

Để gửi kết quả của sự giúp đỡ() để sys .stderr:

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

Lưu ý rằng các tác dụng phụ toàn cầu về sys.stdout có nghĩa là quản lý bối cảnh này không thích hợp để sử dụng trong mã thư viện và ren nhất ứng dụng. Nó cũng không ảnh hưởng đến đầu ra của các tiến trình con. Tuy nhiên, nó vẫn là một cách tiếp cận hữu ích cho nhiều kịch bản tiện ích.

Trình quản lý ngữ cảnh này là reentrant.

Các vấn đề liên quan