On 19 November 2016 at 07:00, Greg Ewing <greg.ew...@canterbury.ac.nz> wrote: > Ram Rachum wrote: >> >> 1. I'm making a program that lets people lease machines. They can issue a >> command to lease 7 machines. ... If everything goes fine, I do pop_all on >> the exit stack so it doesn't get exited and the machines stay leased, > > > Seems to me that would be done more easily and clearly > without involving a context manager at all
ExitStack() handles that case by design - doing "pop_all() gives you a fresh ExitStack() instance, while making close() and __exit__() on the original no-ops. Since ExitStack() deliberately never cleans up the stack implicitly, you end up being able to do: machines = [] with contextlib.ExitStack() as cleanup: for i in range(num_machines_required): machines.append(lease_machine()) cleanup.callback(release_machine, machine) cleanup.pop_all() # It worked, so don't clean anything up yet return machines However, ExitStack *itself* can't readily be written using contextlib.contextmanager - it's not impossible, but it's convoluted enough not to be worth the hassle, since you'd need to do something like: class _ExitStack: # Like the current ExitStack, but without __enter__/__exit__ @contextmanager def exit_stack() state = _ExitStack() try: yield state finally: state.close() Externally, the visible differences would be that: - "es_cm = exit_stack()" and "es_state = exit_stack().__enter__()" would give different results - it would be slower and use more memory due to the additional layer of indirection Since the extra layer of indirection doesn't buy you any new capabilities and has a runtime performance cost, there's no real reason to do it. The general case of that pattern is to yield a state variable that just has a single attribute "needs_cleanup": @contextmanager def my_cm() ... # Do setup operations here state = types.SimpleNamespace(needs_cleanup=True) try: yield state finally: if state.needs_cleanup: ... # Do cleanup operations here However, as with ExitStack, at that point, you're usually going to be better off just implementing __enter__ and __exit__ yourself, and not worrying about using the generator format. This kind of difference in flexibility isn't really specific to context managers though - it's a particular instance of the general pattern that custom classes are often more convenient than closures when you actually *want* to expose externally mutable state. Cheers, Nick. -- Nick Coghlan | ncogh...@gmail.com | Brisbane, Australia _______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/