I think contextlib.ExitStack is Pythonic and canonical and it’s the appropriate solution to this problem. The rest of this answer tries to show the links I used to come to this conclusion and my thought process:
Original Python enhancement request
https://bugs.python.org/issue13585
The original idea + implementation was proposed as a Python standard library enhancement with both reasoning and sample code. It was discussed in detail by such core developers as Raymond Hettinger and Eric Snow. The discussion on this issue clearly shows the growth of the original idea into something that is applicable for the standard library and is Pythonic. Attempted summarization of the thread is:
nikratio originally proposed:
I’d like to propose addding the CleanupManager class described in http://article.gmane.org/gmane.comp.python.ideas/12447 to the contextlib module. The idea is to add a general-purpose context manager to manage (python or non-python) resources that don’t come with their own context manager
Which was met with concerns from rhettinger:
So far, there has been zero demand for this and I’ve not seen code like it being used in the wild. AFAICT, it is not demonstrably better than a straight-forward try/finally.
As a response to this there was a long discussion about whether there was a need for this, leading to posts like these from ncoghlan:
TestCase.setUp() and TestCase.tearDown() were amongst the precursors to__enter__() and exit(). addCleanUp() fills exactly the same role here – and I’ve seen plenty of positive feedback directed towards Michael for that addition to the unittest API…
…Custom context managers are typically a bad idea in these circumstances, because they make readability worse (relying on people to understand what the context manager does). A standard library based solution, on the other hand, offers the best of both worlds:
– code becomes easier to write correctly and to audit for correctness (for all the reasons with statements were added in the first place)
– the idiom will eventually become familiar to all Python users…
…I can take this up on python-dev if you want, but I hope to persuade you that the desire is there…
And then again from ncoghlan a little later:
My earlier descriptions here aren’t really adequate – as soon as I started putting contextlib2 together, this CleanupManager idea quickly morphed into ContextStack [1], which is a far more powerful tool for manipulating context managers in a way that doesn’t necessarily correspond with lexical scoping in the source code.
Examples / recipes / blog posts of ExitStack
There are several examples and recipes within the standard library source code itself, which you can see in the merge revision that added this feature: https://hg.python.org/cpython/rev/8ef66c73b1e1
There is also a blog post from the original issue creator (Nikolaus Rath / nikratio) that describes in a compelling way why ContextStack is a good pattern and also provides some usage examples: https://www.rath.org/on-the-beauty-of-pythons-exitstack.html