1

I have a With statement that I'd like to skip if some <condition> is satisfied. That is, I write:

With MyContext() as mc:
  do_something()

and

class MyContext(object):
...
def __enter__(self,...):
  if <condition>:
    JumpToExit()
def __exit__(self,...):
  print('goodbye')

I would like do_something() to be executed only on certain conditions, otherwise I'd like JumpToExit() to skip the body entirely and just finish the block.

Thanks.

yoki
  • 1,796
  • 4
  • 16
  • 27
  • Or this: [Skipping execution of -with- block](https://stackoverflow.com/questions/12594148/skipping-execution-of-with-block) – Maurice Meyer Mar 05 '20 at 10:23

3 Answers3

2

This is impossible. A with statement cannot cancel the block. However, you could do something like this:

def __enter__(self):
    return condition

Then, when you use the context:

with context as condition:
    if condition:
        ....

If you want to return something else as well you can return a tuple like return condition, self then to use it you can unpack the tuple like with condition, context:.

mousetail
  • 7,009
  • 4
  • 25
  • 45
1

I am not sure that is possible. __enter__ is executed outside of the try block introduced by the with statement, so I don't see a way of jumping directly from __enter__ into __exit__.

with basically (simplified) turns this:

with context as x:
    do_something()

Into

x = context.__enter__()
try:
    do_something()
finally:
    context.__exit__()

You need to throw an exception in do_something() or successfully complete it to get into __exit__. If you do throw an exception from do_something() you can do tricky stuff like suppressing it in the exit function (using some of the parameters passed to it), so you don't actually see it. But it has to be the code inside the with block which somehow causes the jump into __exit__.

Maybe if you can somehow ensure that do_something immediately throws an exception by setting some value in __enter__ you can make it work. But that does not sound like a very good idea to me.

Andreas Vinter-Hviid
  • 1,482
  • 1
  • 11
  • 27
1

You could put the with statement in a function and use return:

def foo():
    With MyContext() as mc:
        if <condition>:
            return None
        do_something()
anurags
  • 87
  • 12