Context Manager without Yield

Unfortunately, the context manager protocol does not give a context manager a way to say "Don't run the with block" (except raising an exception in __enter__). If you're using a context manager anyway, I think your second approach, which has __enter__ return a value to signal if the block should be run is the best approach. If you don't need a context manager for some other reason, you could just use a simple if statement:

if do_stuff:
    # do the stuff

Another option would be to just use a regular generator rather than a contextmanager; a plain generator won't have this restriction. But you'll have to use it with a "for" construct rather than using "with":

def MayNotYield(to_yield):
   if to_yield:
      yield

for _ in MayNotYield(True):
   print('This prints.')

for _ in MayNotYield(False):
   print('This does not.')