如何在 Python 中为 argparse 设置自定义输出处理程序?
How to set custom output handlers for argparse in Python?
我已将 logger
配置为同时打印到终端 stdout
和文件中,这样我就可以拥有一个我可以参考的日志消息存档。
这很容易通过向 logging
对象添加 FileHandler
来实现。简单易行。
我现在想要完成的是使 argparse
也记录到同一个文件,并在遇到解析错误时将其记录到标准输出。到目前为止,它只打印到 stdout
。我查看了 argparse
documentation 但我找不到任何关于为 argparse
.
设置不同的输出流或管道的信息
可以吗?怎么样?
查看 argparse.py source code 似乎没有办法配置此行为。
我的建议是:
- 提交带有补丁的错误报告:)
Override/patch:
print_*
方法
error
方法。
print_*
方法似乎采用可选的 file
参数,默认为 _sys.stdout
。
更新: 或者你可以做这样的事情,在解析参数时临时重定向 sys.stdout
:
from contextlib import contextmanager
@contextmanager
def redirect_stdout_stderr(stream):
old_stdout = sys.stdout
old_stderr = sys.stderr
sys.stdout = stream
sys.stderr = stream
try:
yield
finally:
sys.stdout = old_stdout
sys.stderr = old_stderr
with redirct_stdout_stderr(logstream):
args = parser.parse_args()
似乎无法通过 API 来做到这一点。
但是,您可以执行以下操作:
class LoggingArgumentParser(argparse.ArgumentParser):
"""Custom ArgumentPaarser that overrides _print_message"""
def _print_message(self, message, file=None):
if message:
logger.write(message)
虽然@James Mills 给出的答案很好并且解决了问题,但在这种情况下不需要生成器。因此,yield 是多余的。实现相同目标的另一种方法(没有生成器)是编写自己的 上下文管理器 ,而不使用内置的 contextlib.contextmanager 装饰器。像下面这样。
class redirect_stdout_stderr(object):
def __init__(self, stream):
# Save the old std streams
self.old_stream = sys.stdout
self.old_error_stream = sys.stderr
self.fstream = stream
def __enter__(self):
# Change the std streams to your streams when entering
sys.stdout = self.fstream
sys.stderr = self.fstream
def __exit__(self, exc_type, exc_value, exc_traceback):
# Change the std streams back to the original streams while exiting
sys.stdout = self.old_stream
sys.stderr = self.old_error_stream
对于您的情况,您可以执行以下操作。
with redirect_stdout_stderr(logstream):
# __enter__() is executed
args = parser.parse_args()
# __exit__() is executed
希望对您有所帮助!
我已将 logger
配置为同时打印到终端 stdout
和文件中,这样我就可以拥有一个我可以参考的日志消息存档。
这很容易通过向 logging
对象添加 FileHandler
来实现。简单易行。
我现在想要完成的是使 argparse
也记录到同一个文件,并在遇到解析错误时将其记录到标准输出。到目前为止,它只打印到 stdout
。我查看了 argparse
documentation 但我找不到任何关于为 argparse
.
可以吗?怎么样?
查看 argparse.py source code 似乎没有办法配置此行为。
我的建议是:
- 提交带有补丁的错误报告:)
Override/patch:
print_*
方法error
方法。
print_*
方法似乎采用可选的 file
参数,默认为 _sys.stdout
。
更新: 或者你可以做这样的事情,在解析参数时临时重定向 sys.stdout
:
from contextlib import contextmanager
@contextmanager
def redirect_stdout_stderr(stream):
old_stdout = sys.stdout
old_stderr = sys.stderr
sys.stdout = stream
sys.stderr = stream
try:
yield
finally:
sys.stdout = old_stdout
sys.stderr = old_stderr
with redirct_stdout_stderr(logstream):
args = parser.parse_args()
似乎无法通过 API 来做到这一点。
但是,您可以执行以下操作:
class LoggingArgumentParser(argparse.ArgumentParser):
"""Custom ArgumentPaarser that overrides _print_message"""
def _print_message(self, message, file=None):
if message:
logger.write(message)
虽然@James Mills 给出的答案很好并且解决了问题,但在这种情况下不需要生成器。因此,yield 是多余的。实现相同目标的另一种方法(没有生成器)是编写自己的 上下文管理器 ,而不使用内置的 contextlib.contextmanager 装饰器。像下面这样。
class redirect_stdout_stderr(object):
def __init__(self, stream):
# Save the old std streams
self.old_stream = sys.stdout
self.old_error_stream = sys.stderr
self.fstream = stream
def __enter__(self):
# Change the std streams to your streams when entering
sys.stdout = self.fstream
sys.stderr = self.fstream
def __exit__(self, exc_type, exc_value, exc_traceback):
# Change the std streams back to the original streams while exiting
sys.stdout = self.old_stream
sys.stderr = self.old_error_stream
对于您的情况,您可以执行以下操作。
with redirect_stdout_stderr(logstream):
# __enter__() is executed
args = parser.parse_args()
# __exit__() is executed
希望对您有所帮助!