2011-07-18 27 views
93

Tôi có một dự án lớn bao gồm đủ số lượng mô-đun, mỗi mô-đun in một thứ gì đó với đầu ra tiêu chuẩn. Bây giờ khi dự án đã phát triển về kích thước, không có lớn. của print báo cáo in rất nhiều trên std ra mà đã làm cho chương trình chậm hơn đáng kể.Chuyển hướng stdout thành "không có gì" trong python

Vì vậy, bây giờ tôi muốn quyết định tại thời điểm thời gian chạy có in bất kỳ thứ gì lên thiết bị xuất chuẩn hay không. Tôi không thể thực hiện thay đổi trong các mô-đun như có rất nhiều người trong số họ. (Tôi biết tôi có thể chuyển hướng stdout sang một tệp nhưng ngay cả điều này cũng chậm đáng kể.)

Vì vậy, câu hỏi của tôi là làm thế nào để chuyển hướng stdout thành không có gì tức là làm thế nào để làm cho câu lệnh print không làm gì?

# I want to do something like this. 
sys.stdout = None   # this obviously will give an error as Nonetype object does not have any write method. 

Hiện tại, ý tưởng duy nhất tôi có là tạo lớp học có phương thức ghi (không có gì) và chuyển hướng stdout tới phiên bản của lớp này.

class DontPrint(object): 
    def write(*args): pass 

dp = DontPrint() 
sys.stdout = dp 

Có cơ chế sẵn có trong python cho điều này không? Hay có cái gì tốt hơn thế này?

+0

liên quan: [Redirect stdout to a file in Python?] (Http://stackoverflow.com/q/4675728/4279) – jfs

+1

Tôi vừa phát hiện ra một điều kỳ lạ. Biến sys.stdout thành None không thực sự hoạt động trong chương trình của tôi, mặc dù tôi không chắc tại sao. Tôi đã có * thực sự * vấn đề lạ với mã hóa chuyển hướng đến os.devnull vì vậy tôi đã cố gắng chỉ bằng cách sử dụng None, và nó hoạt động. Có thể có một cái gì đó để làm với tôi làm nó trong một bài kiểm tra đơn vị Django, nhưng tôi không chắc chắn. – Teekin

Trả lời

165

Cross-nền tảng:

import os 
import sys 
f = open(os.devnull, 'w') 
sys.stdout = f 

Trên Windows:

f = open('nul', 'w') 
sys.stdout = f 

Trên Linux:

f = open('/dev/null', 'w') 
sys.stdout = f 
+33

Sử dụng 'os.devnull' thay vì 'nul' hoặc '/ dev/null' và nó sẽ khá dễ dàng. Chỉnh sửa: Để tham khảo: http://docs.python.org/library/os.html#os.devnull – plundra

+3

@plundra - Tôi đã thêm rằng khi tôi nhìn thấy nhận xét của bạn, cảm ơn! –

+0

Làm thế nào để bạn hủy bỏ nó? Có cách nào để bật lại các câu lệnh in sau khi bạn đã hoàn tất không? – jj172

5

Nếu bạn đang ở trong một môi trường Unix (Linux bao gồm), bạn có thể chuyển hướng đầu ra để /dev/null:

python myprogram.py > /dev/null 

Và cho Windows:

python myprogram.py > nul 
+2

Tốt hơn là có giải pháp hoạt động trên tất cả các nền tảng. –

+2

@Guanidene, có lẽ, nhưng nếu anh ấy là người duy nhất sử dụng chương trình của anh ấy, anh ấy có thể đảm bảo khá nhiều cho môi trường. –

1

lớp của bạn sẽ chỉ làm việc tốt (với ngoại trừ tên phương thức write() - nó cần được gọi là write(), chữ thường). Chỉ cần đảm bảo bạn lưu một bản sao của sys.stdout vào một biến khác.

Nếu bạn đang sử dụng * NIX, bạn có thể làm sys.stdout = open('/dev/null'), nhưng điều này ít di động hơn so với việc lăn lớp của riêng bạn.

4

Mở dự án tiếp theo của bạn, sử dụng các module đăng nhập chứ không phải in tào lao để stdout/stderr.

+7

Trong nhiều trường hợp mô đun ghi nhật ký là quá mức cần thiết. Nó chỉ mất hai dòng để chuyển hướng điều kiện stdout thành/dev/null. Nhưng cấu hình đăng nhập để làm bất cứ điều gì hợp lý (như gửi thông tin để stdout, và lỗi để stderr) mất một số lượng vô lý của boilerplate. – DanC

8

(ít nhất là trên hệ thống của tôi), có vẻ như việc viết thư cho os.devnull nhanh hơn khoảng 5x so với ghi vào lớp DontPrint, tức là

#!/usr/bin/python 
import os 
import sys 
import datetime 

ITER = 10000000 
def printlots(out, it, st="abcdefghijklmnopqrstuvwxyz1234567890"): 
    temp = sys.stdout 
    sys.stdout = out 
    i = 0 
    start_t = datetime.datetime.now() 
    while i < it: 
     print st 
     i = i+1 
    end_t = datetime.datetime.now() 
    sys.stdout = temp 
    print out, "\n took", end_t - start_t, "for", it, "iterations" 

class devnull(): 
    def write(*args): 
     pass 


printlots(open(os.devnull, 'wb'), ITER) 
printlots(devnull(), ITER) 

cho đầu ra sau đây:

<open file '/dev/null', mode 'wb' at 0x7f2b747044b0> 
    took 0:00:02.074853 for 10000000 iterations 
<__main__.devnull instance at 0x7f2b746bae18> 
    took 0:00:09.933056 for 10000000 iterations 
+4

Chỉ để ghi lại, lần sau bạn muốn thời gian, chỉ cần sử dụng [timeit] (https://docs.python.org/2/library/timeit.html) –

+4

của khóa học/dev/null là nhanh ... đó là "quy mô web"! –

2

Làm thế nào về điều này:

from contextlib import ExitStack, redirect_stdout 
import os 

with ExitStack() as stack: 
    if should_hide_output(): 
     null_stream = open(os.devnull, "w") 
     stack.enter_context(null_stream) 
     stack.enter_context(redirect_stdout(null_stream)) 
    noisy_function() 

này sử dụng các tính năng trong module contextlib để ẩn đầu ra của bất cứ lệnh bạn đang cố gắng để chạy , tùy thuộc vào kết quả của should_hide_output(), và sau đó khôi phục lại hành vi đầu ra sau khi chức năng đó được thực hiện đang chạy.

Nếu bạn muốn ẩn đầu ra lỗi chuẩn, sau đó nhập redirect_stderr từ contextlib và thêm dòng có dòng stack.enter_context(redirect_stderr(null_stream)).

Nhược điểm chính của nó là điều này chỉ hoạt động trong phiên bản Python 3.4 trở lên.

+1

Thật dễ dàng để hỗ trợ tương tự ['redirect_stdout()' trên các phiên bản Python cũ hơn (ví dụ: sử dụng 'contextlib.contextmanager')] (http://stackoverflow.com/a/22434262/4279). – jfs

9

Cách tốt nhất để làm điều này là tạo một bộ xử lý ngữ cảnh nhỏ mà bạn quấn các bản in của bạn. Sau đó, bạn chỉ cần sử dụng trong một with -statement để tắt tất cả đầu ra.

import os 
import sys 
from contextlib import contextmanager 

@contextmanager 
def silence_stdout(): 
    new_target = open(os.devnull, "w") 
    old_target, sys.stdout = sys.stdout, new_target 
    try: 
     yield new_target 
    finally: 
     sys.stdout = old_target 

with silence_stdout(): 
    print("will not print") 

print("this will print") 

Chạy mã này chỉ in dòng thứ hai của đầu ra, không phải là đầu tiên:

$ python test.py 
this will print 

này hoạt động đa nền tảng (Windows + Linux + Mac OSX), và là sạch hơn so với những người khác câu trả lời imho.

+1

... không phải là máy ghi đè vĩnh viễn 'sys.stdout' này? – celticminstrel

+0

@celticminstrel bạn hoàn toàn đúng, cảm ơn vì đã sửa tôi. Tôi đã cập nhật mã để thiết lập lại sys.stdout sau đó. –

0

Tại sao bạn không thử cái này?

sys.stdout.close() 
sys.stderr.close() 
0

Nếu bạn đang ở trong python 3.4 hoặc cao hơn, có một giải pháp đơn giản và an toàn bằng cách sử dụng thư viện chuẩn:

import contextlib 
import os 

with contextlib.redirect_stdout(None): 
    print("This won't print!") 
+1

'' 'với contextlib.redirect_stdout (Không)' '' hoạt động tốt –

+0

@ChrisCogdon Rất tốt gợi ý, tôi đã chỉnh sửa câu trả lời cho phù hợp. – iFreilicht

0
sys.stdout = None 

Nó là hoàn toàn OK!

Có một note in docs:

Trong một số điều kiện stdin, stdout và stderr cũng như các giá trị ban đầu stdin, stdoutstderr thể là Không có. Nó thường là trường hợp cho các ứng dụng GUI của Windows không được kết nối với bảng điều khiển và Các ứng dụng Python bắt đầu bằng pythonw.

Tôi đã trả lời câu hỏi tương tự here.

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