SoFunction
Updated on 2024-12-11

Explaining python with context manager in detail

As a native Java programmer, it is hard to learn a new language without comparing everything to Java, and Java 7 introduces a new feature that eliminates much of the repetitive code.try-with-resources feature, you don't have to try/finally every time to release resources (the inconvenience is that local variables must be declared before the try, and there is a nested try/catch in the finally to handle exceptions). For example, the following Java code

try(InputStream inputStream = new FileInputStream("")) {
  (());
} catch (Exception ex) {
}

Its corresponding code without the try-with-resources syntax would be

InputStream inputStream = null;
try {
  inputStream = new FileInputStream("");
} catch (Exception ex) {
} finally {
  if(inputStream != null) {
    try {
      ();
    } catch (Exception ex) {
    }
  }
}

Similarly, Python has its own way of writing try-with-resources, the with keyword, which is based on a concept called Context Manager.

The use of the with keyword

with open('some_file', 'w') as opened_file:
  opened_file.write('Hola!')

The above code is equivalent to

opened_file = open('some_file', 'w')
try:
  opened_file.write('Hola!')
finally:
  opened_file.close()

That is, resources opened by the with keyword are automatically released by calling the appropriate method at the end of the with statement block (regardless of whether there is an exception in the with operation).

with is handy to use, but what kind of resources can use the with keyword, and how does Python know which method to call to close a resource? How does Python know which method to call to close a resource, and how do you implement your own Python class that supports a context manager?

Recall again that Java'stry-with-resources Grammar.try(...) The classes supported by the parentheses must be classes that implement theAutoCloseable interface, whose interface methods are

public void close() throws IOException

That is, Java'stry-with-resources The syntax automatically calls these methods to free the resource, so to implement Java that can be freed automatically, you just have to follow this rule.

In Python, there are two implementations of classes that can be with

Classes that implement basic methods to support the context manager

A Python class should be able to be used for with context, must implement at least__enter__ respond in singing__exit__ methods. The meaning of these two methods is well understood, one after creating the resource and the latter after exiting the with after the statement block. See the following example

class File(object):
  def __init__(self, file_name, method):
    self.file_obj = open(file_name, method)
 
  def __enter__(self):
    print("---enter")
    return self.file_obj
 
  def __exit__(self, type, value, traceback):
    print("---exit")
    self.file_obj.close()
 
 
with File('', 'r') as data_file:
  print(data_file.read())

Suppose the contents of the file are

hello
world

Then the output of the above program after execution is

--enter
hello
world
---exit

  1. The value returned by __enter__ is used as the value of the data_file variable in with ... as data_file. as data_file, and if __enter__ doesn't return a value, data_file gets a NoneType object.
  2. __exit__ can be utilized to release resources.
  3. Attempting to execute without the __enter__ method using the with syntax results in an AttributeErro: __enter__ exception.
  4. Similarly, attempting to execute without the __exit__ method using the with syntax will result in an AttributeErro: __exit__ exception.
  5. __exit__ has three additional arguments to get the value of the resource and to handle exceptions in the with block.
  6. The return value of __exit__ is also useful. If it returns True, then the exception is not propagated, otherwise it is thrown directly.

Methods to create support for context managers using generators and decorators

This approach is simpler, although the logical controls are not as strong.

from contextlib import contextmanager
 
@contextmanager
def open_file(name, method):
  f = open(name, method)
  yield f
  ()

The execution code using f will be placed in theyield f The location of thewith Use the above method.yield The f variable will bewith...as variable value after

with open_file('some_file', 'w') as file_object:
  file_object.write('hola!')

Here we also need to pay attention to the exception handling situation, for example, the above code to open the file mode changed to r, still trying to write the file, so in theopen_file methodologicalyield f position will generate an exception that will cause the () Does not get executed and does not release the resource correctly.

Desire to be more defensive, frontyield f It can be extended in the following form

try:
  yield f
except Exception as ex:
  pass #Handle exceptions, or continue to throw them out
finally:
  ()

@contextmanager The decorator is also internally encapsulated into a single implementation of the__enter__ respond in singing__exit__ method of the object.

Reference Links:Context Managers

The above is a detailed explanation of python with context manager, more information about python with context manager please pay attention to my other related articles!