What is the Python “with” statement used for?

后端 未结 3 1660
半阙折子戏
半阙折子戏 2021-01-03 09:09

I am trying to understand the with statement in python. Everywhere I look it talks of opening and closing a file, and is meant to replace the try-finally block. Could someo

相关标签:
3条回答
  • 2021-01-03 09:43

    There's a very nice explanation here. Basically, the with statement calls two special methods on the associated object. The __enter__ and __exit__ methods. The enter method returns the variable associated with the "with" statement. While the __exit__ method is called after the statement executes to handle any cleanup (such as closing a file pointer).

    0 讨论(0)
  • 2021-01-03 09:47

    There are twelve examples of using with in PEP343, including the file-open example:

    1. A template for ensuring that a lock, acquired at the start of a block, is released when the block is left
    2. A template for opening a file that ensures the file is closed when the block is left
    3. A template for committing or rolling back a database transaction
    4. Example 1 rewritten without a generator
    5. Redirect stdout temporarily
    6. A variant on opened() that also returns an error condition
    7. Another useful example would be an operation that blocks signals
    8. Another use for this feature is the Decimal context
    9. Here's a simple context manager for the decimal module
    10. A generic "object-closing" context manager
    11. a released() context to temporarily release a previously acquired lock by swapping the acquire() and release() calls
    12. A "nested" context manager that automatically nests the supplied contexts from left-to-right to avoid excessive indentation
    0 讨论(0)
  • 2021-01-03 09:48

    The idea of the with statement is to make "doing the right thing" the path of least resistance. While the file example is the simplest, threading locks actually provide a more classic example of non-obviously buggy code:

    try:
        lock.acquire()
        # do stuff
    finally:
        lock.release()
    

    This code is broken - if the lock acquisition ever fails, either the wrong exception will be thrown (since the code will attempt to release a lock that it never acquired), or, worse, if this is a recursive lock, it will be released early. The correct code looks like this:

    lock.acquire()
    try:
        # do stuff
    finally:
        # If lock.acquire() fails, this *doesn't* run
        lock.release()
    

    By using a with statement, it becomes impossible to get this wrong, since it is built into the context manager:

    with lock: # The lock *knows* how to correctly handle acquisition and release
      # do stuff
    

    The other place where the with statement helps greatly is similar to the major benefit of function and class decorators: it takes "two piece" code, which may be separated by an arbitrary number of lines of code (the function definition for decorators, the try block in the current case) and turns it into "one piece" code where the programmer simply declares up front what they're trying to do.

    For short examples, this doesn't look like a big gain, but it actually makes a huge difference when reviewing code. When I see lock.acquire() in a piece of code, I need to scroll down and check for a corresponding lock.release(). When I see with lock:, though, no such check is needed - I can see immediately that the lock will be released correctly.

    0 讨论(0)
提交回复
热议问题