I've tried classes, decorators, and passing the conditional using 'as', as suggested by Michael, so I disagree that with is not suitable here since I have yet to find a better alternative. If you want I can give pretty concrete examples in the ways they aren't as good. Furthermore, I think it could be argued that it makes more sense to be able to safely skip the with body without the user of the with statement having to manually catch the exception themselves.... we don't make people catch the StopIteration exception manually when using iterators...
1) I can't think of many instances in python where a block of code can not be conditionally executed safely:
if - obvious
functions - need to be called
loops - can have 0 or more iterations
try/except/finally - even here there is the same notion of the code blocks being conditionally executed, just a bit more scrambled
in my view, the 'with' statement exists just because it is nice sugar for bracketing boilerplate around a block of code, so it might as well do that in the most general, reasonable way. And I think this behavior is pretty reasonable.
On Feb 29, 2012, at 06:07 AM, Tal Einat
So I've recently been trying to implement something for which I had hoped the 'with' statement would be perfect, but it turns out, won't work because Python provides no mechanism by which to skip the block of code in a with statement.
I want to create some functionality to make it easy too wrap command line programs in a caching architecture. To do this there are some things that need to happen before and after the wrapped CLI program is called, a try,except,finally version might look like this:
def cachedcli(*args): try: hashedoutput = hashon(args) if iscached(): return hashedoutput acquirelock() cli(*args,hashedoutput) iscached(True) return hashedoutput except AlreadyLocked: while locked: wait() return example(*args) finally: releaselock()
the 'with' version would look like
def cachedcli(*args) hashedpath = hashon(args) with cacheon(hashedpath): cli(hashedpath,*args) return hashedpath
So obviously the 'with' statement would be a good fit, especially since non-python programmers might be wrapping their CLI programs... unfortunately I can't use 'with' because I can't find a clean way to make the with block code conditional.
PEP377 suggested some mechanics that seemed a bit complicated for getting the desired effect, but I think, and correct me if I'm wrong, that the same effect could be achieved by having the __enter__ function raise a StopIteration that would be caught by the context and skip directly to the __exit__ function. The semantics of this even make some sense too me, since the closest I've been able to get to what I had hoped for was using an iterator to execute the appropriate code before and after the loop block:
def cachedcli(*args) hashedpath = hashon(args) for _ in cacheon(hashedpath): cli(hashedpath,*args) return hashedpath
this still seems non-ideal to me...
Specifically with regard to caching, I recommend writing a CLI execution class which implements the caching logic internally. If you really want to do this with some special syntax sugar, use decorators, which are good for wrapping functions/methods with caching. The "with" statement is IMO not suitable here (and rightfully so). - Tal Einat