下面粘贴的代码执行以下操作:
meta_path
并在退出时清除。现在我想知道在这种情况下使用上下文管理器是否是一个好主意,因为实际上我没有标准try/finally
流程,只是设置和清理。
另一件事 - 用这一行:
with CollectorContext(cl, sys.argv, 'imports.log') as cc:
cc
成为None
吗?它不应该是CollectorContext
对象吗?
from __future__ import with_statement
import os
import sys
class CollectImports(object):
"""
Import hook, adds each import request to the loaded set and dumps
them to file
"""
def __init__(self):
self.loaded = set()
def __str__(self):
return str(self.loaded)
def dump_to_file(self, fname):
"""Dump the loaded set to file
"""
dumped_str = '\n'.join(x for x in self.loaded)
open(fname, 'w').write(dumped_str)
def find_module(self, module_name, package=None):
self.loaded.add(module_name)
class CollectorContext(object):
"""Sets the meta_path hook with the passed import hook when
entering and clean up when exiting
"""
def __init__(self, collector, argv, output_file):
self.collector = collector
self.argv = argv
self.output_file = output_file
def __enter__(self):
self.argv = self.argv[1:]
sys.meta_path.append(self.collector)
def __exit__(self, type, value, traceback):
# TODO: should assert that the variables are None, otherwise
# we are quitting with some exceptions
self.collector.dump_to_file(self.output_file)
sys.meta_path.remove(self.collector)
def main_context():
cl = CollectImports()
with CollectorContext(cl, sys.argv, 'imports.log') as cc:
progname = sys.argv[0]
code = compile(open(progname).read(), progname, 'exec')
exec(code)
if __name__ == '__main__':
sys.argv = sys.argv[1:]
main_context()
答案 0 :(得分:3)
我认为这个概念没问题。同样,我没有看到任何理由反对在finally:
子句中使用清理内容,因此上下文管理器非常适合。
您的cc
是None
,因为您说的是as
。
如果您不想这样做,请更改__enter__
method to return something else:
此方法返回的值使用此上下文管理器绑定到
with
语句的def __enter__(self): self.argv = self.argv[1:] sys.meta_path.append(self.collector) return self # or return self.collector # or return "I don't know what to return here"
子句中的标识符。
with CollectorContext(cl, sys.argv, 'imports.log') as cc:
print cc, repr(cc) # there you see what happens.
progname = sys.argv[0]
code = compile(open(progname).read(), progname, 'exec')
exec(code)
然后
{{1}}
答案 1 :(得分:2)
如果您始终希望进行清理,则应使用上下文管理器。如果使用低级特殊方法实现上下文管理器,我不确定在哪里使用try..finally
。如果您使用@contextmanager装饰器,则以“自然”方式对上下文管理器进行编码,这样您就可以使用try..finally
而不是将异常作为参数。
此外,cc
将是您从__enter__()
返回的值。在您的情况下,None
。我理解上下文管理器设计的方式是返回值是“上下文”。上下文管理器所做的是设置和清理其他事件发生的上下文。例如。数据库连接将创建事务,数据库操作发生在这些事务的范围内。
那就是说,上面就是为了提供最大的灵活性。如果您不需要使用self
中的上下文值,直接创建上下文(自行管理)并返回with
,甚至不返回任何内容都没有错。由于您不在任何地方使用cc
,您可以这样做而不用担心返回值:
with CollectorContext(cl, sys.argv, 'imports.log'):
progname = sys.argv[0]
code = compile(open(progname).read(), progname, 'exec')
exec(code)
答案 2 :(得分:1)
感谢大家现在它运作顺利,我实际上想要返回一些内容,因为我想在上下文管理器中封装“run”,所以我得到如下内容。
此外,现在我存储旧的sys.argv并在退出时恢复它,可能不是基本的但是仍然是一件好事我想...
class CollectorContext(object):
"""Sets the meta_path hook with the passed import hook when
entering and clean up when exiting
"""
def __init__(self, collector, argv, output_file):
self.collector = collector
self.old_argv = argv[:]
self.output_file = output_file
self.progname = self.old_argv[1]
def __enter__(self):
sys.argv = self.old_argv[1:]
sys.meta_path.append(self.collector)
return self
def __exit__(self, type, value, traceback):
# TODO: should assert that the variables are None, otherwise
# we are quitting with some exceptions
self.collector.dump_to_file(self.output_file)
sys.meta_path.remove(self.collector)
sys.argv = self.old_argv[:]
def run(self):
code = compile(open(self.progname).read(), self.progname, 'exec')
exec(code)
def main_context():
cl = CollectImports()
with CollectorContext(cl, sys.argv, 'imports.log') as cc:
cc.run()