干净地(可选)将stderr或stdout重定向到文件 [英] Cleanly and optionally redirect stderr or stdout to file
问题描述
我有一个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计算文件名,并且我不想在各种外壳中重新计算它们.而且,我也不想提出是否重定向的逻辑在shell脚本中.如果可能,我希望在我的主代码中有这些分支.)
尝试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并没有对我大吼大叫,但我仍然忍不住觉得它不太像Pythonic,而且我也不完全确定它的安全性.我在奇怪的方向上推动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
(可选)将程序的stdout
或stderr
重定向到文件的最简洁的方法是,根本不要在程序中这样做.相反,请通过操作系统的外壳进行操作.
在Linux上,如果我想将Python程序的stdout
重定向到文件,我' d为此:
$ python something.py > stdout.log
$ python something_else.py 2> stderr.log
请注意2>
用于重定向stderr
输出.
发生这种情况时, cmd
和内置的print
函数实际上有一个命名参数"file
",可让您决定将print
放置在何处.
print(some_object, file=your_own_file_object)
file
可以是任何类似文件的对象(stdout
和stderr
是).您可以只传递 open()
的结果,否则就会发疯并使用 io
模块.无论哪种情况,您都只需要维护一个变量(其值可能是sys.stdout
的值),并始终将其传递给print
调用,然后只要您决定将输出内容输出到哪里,就只需设置该变量即可.>
否则,您可以考虑设置 sys.stdout
和sys.stderr
,如果您不介意从其他Python程序员那里获得有趣的表情的话.
I have a Python3 script and I want to optionally redirect stdout
and stderr
to a file. Something like this:
# 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()
This works, unless my code in the middle decides to quit. Then my files aren't guaranteed to be closed. How can I cleanly close these files no matter what happens in the code and only some of the time? (Normally, I would redirect through the shell, but I'm computing the file names in Python and I don't want to recompute them in various shells. Also, I don't want to put the logic for whether or not to redirect in a shell script. I want those branches in my main code if possible.)
Attempt 1
It seems like context managers would be the way to here, but, when I try to use them, I have to rewrite my code several times and it's not pretty code:
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
Attempt 2
I decided to make a context manager for it. I think it works, and Python's not yelling at me, but I still can't help but feel it's not too Pythonic and I'm not completely sure it's safe. I'm pushing the if
statements in odd directions. Is there a better way?
@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
The cleanest way to optionally redirect your program's stdout
or stderr
to a file is to not do so in your program at all. Instead, do it through your operating system's shell.
On Linux, if I wanted to redirect a Python program's stdout
to a file, I'd do this:
$ python something.py > stdout.log
$ python something_else.py 2> stderr.log
Note the 2>
for redirecting stderr
output.
As it happens, cmd
and PowerShell on Windows use the same syntax.
The above, while true, isn't relevant given the OP's updated problem description.
Assuming you're using Python 3, the built-in print
function actually has a named parameter "file
" that lets you decide where to print
to.
print(some_object, file=your_own_file_object)
file
can be any file-like object (which stdout
and stderr
are). You could just pass in the result of open()
, or get crazy and screw around with the io
module. Whatever the case, you just have to maintain a variable (whose value is possibly that of sys.stdout
) and always pass that in to print
calls, and then just set that variable whenever you decide where to output something to.
Otherwise, you might considering setting the value of sys.stdout
and sys.stderr
, if you don't mind getting funny looks from other Python programmers.
这篇关于干净地(可选)将stderr或stdout重定向到文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!