我试过了:
@contextmanager
def changed_dir(dirname, msg="nothing to do.."):
if changed(dirname):
yield
else:
print msg
return
然而,当我尝试使用它时:
with changed_dir("foo/bar"):
print "something in foo/bar was changed"
我受到了欢迎:
RuntimeError: generator didn't yield
有什么方法可以让它发挥作用吗?
更新:很多人似乎都被这个例子简单化了。这是一个更复杂的例子,说明了同一点
@contextmanager
def changed_dir(dirname, msg="..."):
cn = db.get_connection(...)
try:
cn.execute("insert ...")
if changed(dirname):
cn.execute(...)
yield
os.mkdirs(os.path.join('backup', dirname))
# copy the modified tree..
# etc.
else:
cn.execute(...)
print msg
cn.commit()
except:
cn.rollback()
# cleanup from mkdirs call...
finally:
cn.close()
是否仍然是上述唯一的解决方案?
答案 0 :(得分:1)
Guido在PEP-0343中的评论似乎表明这个用例是copacetic,并且基于我提出的pep示例(我查看了来自@ Cyphase的答案的链接,但这似乎不必要地复杂化):< / p>
class changed_dir(object):
class NoChange(ValueError):
pass
def __init__(self, dirname, msg="nothing to do"):
self.dirname = dirname
self.msg = msg
def __enter__(self):
if changed(self.dirname):
return
else:
print self.msg
raise changed_dir.NoChange()
def __exit__(self, type, value, traceback):
return isinstance(value, changed_dir.NoChange)
这看起来像大多数上下文管理器一样简单(但不像我可以使用装饰器那样简单。)
答案 1 :(得分:0)
It's possible,但你可能不应该这样做。使用if/else
。实际上,只需使用上下文管理器中的if/else
。
msg = "nothing to do.."
if changed(dirname):
print "something in foo/bar was changed"
else:
print msg
<强>更新强>
在回复您的更新时,我会如何做到这一点:
@contextmanager
def db_context_manager(): # Name this better
cn = db.get_connection(...)
try:
cn.execute("insert ...")
yield
cn.commit()
except:
cn.rollback()
finally:
cn.close()
with db_context_manager():
if changed(dirname):
do_stuff()