2016-10-05 75 views
0

我正在使用上下文管理器來包裝將顯示在終端中並同時寫入文件的文本。文件中的上下文管理器I/O操作

我面對這個問題,並得到了解決,請 Writing terminal output to terminal and to a file?

無法更改的問題是功能(等FUNC1和FUNC2)的「與」陳述的任何輸出作爲sys.stdout.write函數的表演過後值錯誤:在關閉的文件I/O操作

示例代碼:

import sys, datetime 

class FileWrite(object): 
    def __init__(self,log_file_name, stdout): 

     self.log_file_name = log_file_name 
     self.stdout = stdout 

    def __enter__(self): 
     self.log_file = open(self.log_file_name, 'a', 0) 
     return self 

    def __exit__(self, exc_type, exc_value, exc_traceback): 
     self.log_file.close() 

    def write(self, data): 
     self.log_file.write(data) 
     self.stdout.write(data) 
     self.stdout.flush() 
def func1(): 
    sys.stdout.write('A') 
def func2(): 
    sys.stdout.write('B') 
def main(): 
    with FileWrite(..........., sys.stdout) as sys.stdout: 
     func1() 
     func2() 



    sys.stdout.write('test') 

main() 
............................ 
# both output A and B is showing in terminal and writing in file 
............................ 
# writing 'test' only in terminal...... 
I/O operation in closed file 

回答

2

您並不需要(或不想)在這裏使用as。如果目標是將任何寫入轉換爲sys.stdout寫入到sys.stdout和您的日誌文件,則需要備份sys.stdout__enter__並將其恢復到__exit__,但不要明確地將sys.stdout傳遞給構造函數,並且不要使用__enter__返回替換sys.stdout,因爲它繞過了__enter__/__exit__代碼。相反,有__enter____exit__爲你做替換工作:

class tee_stdout(object): 

    def __init__(self, log_file_name): 
     self.log_file_name = log_file_name 
     self.stdout = None 

    def __enter__(self): 
     self.log_file = open(self.log_file_name, 'a', 0) 

     # Replace sys.stdout while backing it up 
     self.stdout, sys.stdout = sys.stdout, self 

    def __exit__(self, exc_type, exc_value, exc_traceback): 
     sys.stdout = self.stdout # Restore original sys.stdout 
     self.log_file.close() 

    def write(self, data): 
     self.log_file.write(data) 
     self.stdout.write(data) 
     self.stdout.flush() 

現在,用法就是:

with tee_stdout(logfilename): 
    ... do stuff that uses sys.stdout, explicitly or implicitly ... 
... when block exits, sys.stdout restored, so normal behavior resumes ... 

注意:如果您的目標的Python 3.4或更高版本,我建議實施只有write,然後用contextlib.redirect_stdout類,以避免重新發明輪子:

from contextlib import redirect_stdout 

class tee_output: 
    def __init__(self, *targets): 
     self.targets = targets 
    def write(self, data): 
     for tgt in self.targets: 
      tgt.write(data) 
      tgt.flush() 

with open(logfilename, 'a') as log, redirect_stdout(tee_output(log, sys.stdout)): 
    ... logs to logfilename and sys.stdout when sys.stdout written to ... 
... undoes redirection ... 

注:以上所有ASI de,通常情況下,你只需要使用the logging module和記錄器方法就可以實現這樣的功能。您可以預先配置不同的記錄器,其中一些記錄器可以轉至sys.stdout,一些轉至日誌文件,sys.stdout,一些僅用於記錄文件,並在需要時使用適當的記錄器。

1

with FileWrite(..........., sys.stdout) as sys.stdout:

您正在覆蓋sys.stdout,只是爲您的文件選擇了一個真實的名稱,如outputsys.stdout

例子:

with FileWrite(..........., sys.stdout) as output: 
    output.write('A') 
    output.write('B') 
sys.stdout.write("test") 

編輯
既然你真的不希望在標準輸出寫,傳遞你FileWrite實例作爲參數傳遞給你的方法。

def func1(output): 
    output.write('A') 

with FileWrite(..........., sys.stdout) as output: 
    func1(output) 

對func2也一樣。

+0

你能舉個例子嗎 – mortuzahasan

+0

這個工作適合你嗎? –

+0

是的。它不寫入文件,而'做一些寫作' – mortuzahasan