Python標準出力sys.stdoutリダイレクト

8266 ワード

本環境:Python 2.7
print(obj)ではなくprint objを使用する
 
いくつかの背景
sys.stdoutとprint
Pythonで印刷オブジェクトがprint objを呼び出すと、実際にsysが呼び出されます.stdout.write(obj+'')
printは必要な内容をコンソールに印刷し、改行を追加しました.
printはsysを呼び出すstdoutのwriteメソッド
次の2行は事実上等価です.
sys.stdout.write('hello'+'
') print 'hello'

sys.stdinとraw_input
raw_を使うとInput('Input promption:')では、実際にプロンプト情報を出力し、入力をキャプチャします
次の2つのグループは事実上等価です.
hi=raw_input('hello? ')



print 'hello? ', #comma to stay in the same line

hi=sys.stdin.readline()[:-1] # -1 to discard the '
' in input stream

 
コンソールからファイルにリダイレクト
元のsys.stdout指向コンソール
ファイルのオブジェクトの参照をsysに割り当てると.stdout、printが呼び出すのはファイルオブジェクトのwriteメソッドです
f_handler=open('out.log', 'w')

sys.stdout=f_handler

print 'hello' 

# this hello can't be viewed on concole

# this hello is in file out.log

コンソールで何かを印刷したい場合は、元のコンソールオブジェクトリファレンスを保存し、ファイルに印刷してからsysを復元したほうがいいことを覚えておいてください.stdout
__console__=sys.stdout



# redirection start

# ...

# redirection end



sys.stdout=__console__

コンソールとファイルにリダイレクト
印刷したコンテンツをコンソールに出力し、ファイルをログとして保存したい場合は、どうすればいいですか?
印刷するとbufferがリフレッシュを解放するのではなく、印刷された内容をメモリに保持します.文字列領域に配置するとどうなりますか?
a=''

sys.stdout=a

print 'hello'

OK、上記のコードは正常に動作しません
Traceback (most recent call last):

  File ".\hello.py", line xx, in <module>

    print 'hello'

AttributeError: 'str' object has no attribute 'write'

エラーは明らかです.上で強調したようにsysを呼び出してみました.stdout.write()のとき、writeメソッドがないことに気づきました
また、ここで関数が見つからないのではなくattribute errorを提示するのは、pythonがオブジェクト/クラスの関数ポインタをオブジェクト/クラスの属性として記録しているためだと思いますが、関数のエントリアドレスが残っているだけです
それなら、リダイレクトしたオブジェクトにwriteメソッドを実装する必要があります.
import sys



class __redirection__:

    

    def __init__(self):

        self.buff=''

        self.__console__=sys.stdout

        

    def write(self, output_stream):

        self.buff+=output_stream

        

    def to_console(self):

        sys.stdout=self.__console__

        print self.buff

    

    def to_file(self, file_path):

        f=open(file_path,'w')

        sys.stdout=f

        print self.buff

        f.close()

    

    def flush(self):

        self.buff=''

        

    def reset(self):

        sys.stdout=self.__console__

        



if __name__=="__main__":

    # redirection

    r_obj=__redirection__()

    sys.stdout=r_obj

    

    # get output stream

    print 'hello'

    print 'there'

    

    # redirect to console

    r_obj.to_console()

    

    # redirect to file

    r_obj.to_file('out.log')

    

    # flush buffer

    r_obj.flush()

    

    # reset

    r_obj.reset()

同じだstderr, sys.stdinも複数のアドレスにリダイレクトできるので、一反三のことは自分で実践しましょう