0

Python3 スクリプトがあり、必要に応じてファイルにリダイレクトstdoutしたいと考えstderrています。このようなもの:

# variable declarations
if log_output:
    output_file = open('output.txt', 'w')
    sys.stdout = output_file

if log_errors:
    errors_file = open('errors.txt', 'w')
    sys.stderr = errors_file

# code that uses variables declared above but may exit suddenly

#at the end
if log_output:
    output_file.close()

if log_errors:
    errors_file.close()

途中の私のコードが終了することを決定しない限り、これは機能します。次に、ファイルが閉じていることが保証されていません。コードで何が起こっても、これらのファイルをきれいに閉じるにはどうすればよいですか? (通常、シェル経由でリダイレクトしますが、Pythonでファイル名を計算していて、さまざまなシェルで再計算したくありません。また、リダイレクトするかどうかのロジックを入れたくありませんシェルスクリプトで. 可能であれば、メインコードにそれらのブランチが必要です.)

試行 1

コンテキストマネージャーがここまでの道のりのようですが、それらを使用しようとすると、コードを何度も書き直す必要があり、きれいなコードではありません。

if log_output:
    with open('output.txt', 'w') as output_file:
        with contextlib.redirect_stdout(output_file):
            if log_errors:
                with open('errors.txt','w') as errors_file:
                    with contextlib.redirect_stderr(errors_file):
                        # log_output and log_errors
                        # code that uses variables declared above but may exit suddenly
            else:
                # log_output and not log_errors
                # code that uses variables declared above but may exit suddenly
else:
    if log_errors:
        with open('errors.txt', 'w') as errors_file:
            with contextlib.redirect_stderr(errors_file):
                # not log_output and log_errors
                # code that uses variables declared above but may exit suddenly
    else:
        # not log_output and not log_errors
        # code that uses variables declared above but may exit suddenly

試行 2

そのためのコンテキストマネージャーを作成することにしました。私はそれがうまくいくと思うし、Python は私に怒鳴っていない. 私はif声明を奇妙な方向に押し進めています。より良い方法はありますか?

@contextlib.contextmanager
def opt_stream(stream, name = None):
    if name:
        file = open(name,'w')
        yield file
        file.close()
    else:
        yield stream

output_name, errors_name = None, None

if log_output:
    output_name = 'outputs.txt'
if log_errors:
    errors_name = 'errors.txt'

with opt_stream(sys.stdout, output_name) as output_file:
    with opt_stream(sys.stderr, errors_name) as errors_file:
        with contextlib.redirect_stdout(output_file):
            with contextlib.redirect_stderr(errors_file):
                # code that uses variables declared above but may exit suddenly
4

1 に答える 1