假设我想要实现具有以下签名的Python脚本:
myscript.py INPUT OUTPUT
…其中INPUT
和OUTPUT
分别代表文件的路径,脚本将分别读取和写入
用于实现具有这种签名的脚本的代码可以具有以下构造:
with open(inputarg, 'r') as instream, open(outputarg, 'w') as outstream:
...
…其中inputarg
和outputarg
变量保存通过其INPUT
和OUTPUT
命令行参数传递给脚本的文件路径(即字符串)
到目前为止没有什么特别或不寻常的
但是现在,假设对于脚本的版本2,我想给用户一个选项,为它的任一(或两者)参数传递特殊值-
,以指示脚本应该分别从stdin
读取和写入stdout
换句话说,我希望下面的所有表格都能产生相同的结果:
myscript.py INPUT OUTPUT
myscript.py - OUTPUT <INPUT
myscript.py INPUT - >OUTPUT
myscript.py - - <INPUT >OUTPUT
现在,前面给出的with
语句不再适用。首先,表达式open('-', 'r')
或open('-', 'w')
都会引发异常:
FileNotFoundError: [Errno 2] No such file or directory: '-'
我还没有想出一种方便的方法来扩展上面基于with
的结构,以适应所需的新功能
例如,这种变体不起作用(除了有些笨拙),因为sys.stdin
和sys.stdout
没有实现上下文管理器接口:
with sys.stdin if inputarg == '-' else open(inputarg, 'r'), \
sys.stdout if outputarg == '-' else open(outputarg, 'w'):
...
我唯一能想到的(也许)是定义一个实现上下文管理器接口的最小传递包装器类,如下所示:
class stream_wrapper(object):
def __init__(self, stream):
self.__dict__['_stream'] = stream
def __getattr__(self, attr):
return getattr(self._stream, attr)
def __setattr__(self, attr, value):
return setattr(self._stream, attr, value)
def close(self, _std=set(sys.stdin, sys.stdout)):
if not self._stream in _std:
self._stream.close()
def __enter__(self):
return self._stream
def __exit__(self, *args):
return self.close()
…然后像这样写with
语句:
with stream_wrapper(sys.stdin if inputarg == '-' else open(inputarg, 'r')), \
stream_wrapper(sys.stdout if outputarg == '-' else open(outputarg, 'w')):
...
这个stream_wrapper
类给我的印象是,它所取得的成就非常戏剧化(假设它能工作:我还没有测试过它!)
有没有更简单的方法获得相同的结果
重要提示:此问题的任何解决方案都必须注意不要关闭sys.stdin
或sys.stdout
使用contextlib.contextmanager可以通过以下方式进行管理:
如果不熟悉
contextmanager
,它基本上会在进入时运行到yield
,在退出时运行到yield
之后。在with
中包装open
的yield
可以确保它在使用时是关闭的相关问题 更多 >
编程相关推荐