Python context management (Context Manager) and contextlib quick start
In Python development, resource management is almost everywhere: open files, database connections, network requests, temporary directories... These resources all have one thing in common: they must be released when used up. If you only write "Get resources → Use resources" in the code, once an exception is thrown in the middle, the cleanup code will be skipped, which will waste memory at best, and cause serious problems such as file handle leaks and connection pool exhaustion. This article takes you from the originaltry...finallygradually evolve towithstatement and powerfulcontextlibModule, write safe, concise, Pythonic resource management code.
1. Why should we pay attention to resource management?
Imagine the simplest file reading scenario:
ifread()Throws an exception (such as file corruption or disk error) and the program crashes directly,close()No chance at all to execute. The file handle is occupied, which means that the file cannot be accessed after the program is restarted, or that the file descriptors of the entire process are exhausted.
The most original remedy is to usetry...finallyForced to tell the truth:
In this way, even if an error occurs midway, cleanup will be performed. But the shortcomings are also obvious: cleaning logic and business logic are mixed, the code is bloated, and you have to remember to judge every timefWhether created successfully.
2. Python native solution:withstatement
Python 2.5 introducedwithSyntactic sugar, specifically solving the "enter-use-exit" pattern. The above example can be simplified to:
Two lines of code complete the safe opening and automatic closing of files, even ifread()Throw an exception,f.close()will also be called. This writing method is both concise and safe, and is the resource management method recommended by Python.
3. What objects can be put in?with? Contextual protocol!
Only objects that implement the Context Management Protocol can interact withwithused together. The protocol requires the object to provide two magic methods:
3.1 Handwrite a database connection context class
Let’s understand these two methods through an example of simulating a database connection:
After running, you will find that evenquery()If an error occurs, the log of the closed connection will also be output, ensuring that the resources will be released.
4. UsecontextlibBeing Lazy: How to Avoid Handwriting Magic
Realize it with your own hands__enter__and__exit__Very clear, but too formal in some simple scenes.contextlibThe standard library provides several shortcuts that allow you to create context managers with very little code.
4.1 Most commonly used:@contextmanagerDecorator
@contextmanagerA ** can be includedyieldThe generator function ** is converted directly into the context manager. The execution flow of the generator corresponds to the three steps of the context manager:
yieldbefore part →__enter__logicyieldThe value that comes out →__enter__return value (forasuse)yieldAfter part →__exit__Logic (must be usedtry...finallypackage, otherwise the cleanup code will not be executed when an exception occurs)
Rewrite the database connection with a generator
A more intuitive example: HTML tag nesting
If you only need to switch environments (or states) when entering and exiting, the generator writing method is especially elegant:
Output result:
4.2 Adapter tool:closing()
Many third-party library objects provideclose()method, but does not implement the context management protocol, such as the early built-inurllib.request.urlopen. It can be used at this timeclosing()Give it a "shell":
closing()The object will be automatically called when exitingclose()method regardless of whether an exception occurs.
4.3 Batch management tools:ExitStack
If you need to manage an undetermined number of dynamic contexts at the same time (such as looping open files), use nestingwithIt would be very troublesome or even impossible.ExitStackThis is what it’s made for:
ExitStackEach context will be automatically called in reverse order of entry.__exit__Method that cleans up all resources correctly even if something goes wrong along the way.
5. Modern Python Best Practices
Once you master context managers, you can incorporate the following principles into your daily coding:
- can be used
withNo needtry...finally. Files, locks, database sessions, network connections, etc. should all be enteredwith"protective umbrella". - Make good use of
contextlibReduce template code. For simple scenes@contextmanager, used to adapt to old interfacesclosing(), for dynamic resource managementExitStack。 - The way to write the generator must be
try...finally. otherwiseyieldThe cleanup code may never execute afterwards. - ** Give with caution
__exit__returnTrue**. Unless you absolutely need to swallow an exception, let it propagate up normally to avoid hiding errors. - Type annotation improves readability. Python 3.6+ available
typing.ContextManager, 3.9+ is still availablecontextlib.AbstractContextManagerAnnotate your context manager return type.
6. Two extremely practical practical cases
6.1 Automatically delete temporary directories
Temporary directories are often needed for testing or data processing and should be deleted after use.tempfile.mkdtempYou are only responsible for creation, and you have to delete it yourself, which is easy to forget. use@contextmanagerWrap it up and sit back and relax:
6.2 Automatic commit/rollback of database transactions
When operating databases in web development, we often hope that "a batch of operations will either succeed or fail." Transaction behavior can be easily encapsulated using context managers:
When using it, just put the database operation inwith auto_transaction(session):Within the block, all successful operations are automatically submitted, and errors are automatically rolled back.
Summarize
Context managers are the cornerstone of Python resource management. from manualtry...finallyto elegantwith, and then to the standard librarycontextlibWith various auxiliary tools provided, your code will become more secure, concise and readable. Next time you encounter a scene that requires "open-use-close", you might as well ask yourself: Can it be used?withDone? **
Most of the time, the answer is yes.

