Do you really understand python's with statement?

Posted by diesel_heart on Wed, 29 May 2019 21:43:10 +0200

Why use the with statement?

The following three points, especially the first one, I think are very important.^^

  1. Make your python code look pythonic
  2. Simplify try/final mode and reduce the number of template code
  3. Code is more secure and easier to use

Let's review try / final mode first.

Now that we're talking about simplifying try/finally mode with, let's take a look at what it looked like before simplifying.

#! /usr/bin/env python
# -*- coding: utf-8 -*-

def create_file_by_try(file):
    try:
        f = open(file, 'w')
        f.write("A create file demo")
    except Exception as e:
        print(e.with_traceback())
    finally:
        f.close()

if __name__ == "__main__":
    create_file_by_try('demo.txt')

If you're a developer from Java and C++, you might feel that this code is simple enough, but if you follow the tenet of The zen of python, it's far from concise enough. At the same time, this code also has security risks, such as: if the parameter passed in is not demo.txt but an empty address, although try protects f = Open (file,'w'), f. wri. Te ("A create file demo") these two lines of code, but f.close() in the final block, or because f is not assigned, resulting in throwing exceptions, then we have to add try/except in the final block for the sake of code robustness? Looking at the following slightly more robust code, do you think it's sufficiently concise?

#! /usr/bin/env python
# -*- coding: utf-8 -*-

def create_file_by_try2(file):
    try:
        f = open(file, 'w')
        f.write("A create file demo.")
    except Exception as e:
        print(e)
    finally:
        try:
            f.close()
        except Exception as e :
            print(e)

if __name__ == "__main__":
    create_file_by_try2('')

Now let's see how concise with is.

#! /usr/bin/env python
# -*- coding: utf-8 -*-

def create_file_by_with(file):
    with open(file, 'w') as f:
        f.write("A new create file demo.")

if __name__ == "__main__":
    create_file_by_with('demo.txt')

Looking at the two implementations, you will find that there are 2/3 fewer template codes using with statements, and there is no need for manual cleaning operations such as close, so the code is not only much simpler, but also the code risk is reduced.

Since with is so wonderful, how can we use it more widely?

The above is only a simple use of with, not its principle, if we want to use it more widely, we must understand its principle. When it comes to the context manager associated with with, what is a context manager?

Context Manager

Context manager is the object that implements the context manager protocol, which is called context manager. The context manager protocol is also involved here.
Context Manager Protocol: Includes _enter_ and _exit_ methods. So simply explain that if an object implements _enter_ and _exit_ methods, then this class is a context manager.

Context Manager in with Statement

When the with statement starts running, it creates a temporary context, which is controlled by the context manager. At the same time, it calls the _enter_ method of the context manager, and _enter_ has a return value, which is assigned to the object after as, such as the f object in with open (file,'w') as f. Note that the value assigned to f here is not the return value of the open function, but the return value of _enter_. If the return value of _enter_ is empty, the with statement can omit the as statement. At the end of the with statement, the _exit_ method is called, which is mainly used for cleaning up.

Implement your own context manager

Customize a context manager my_context.py:

#! /usr/bin/env python
# -*- coding: utf-8 -*-

class MyContext(object):
    def __enter__(self):
        print('run __enter__')
        return "I am MyContext.__enter__ Return value"

    '''
    :exc_type Type of exception
    :exc_val Value content of exception
    :exc_tb Abnormal Call Link Information
    '''
    def __exit__(self, exc_type, exc_val, exc_tb):
        print('run __exit__')
        # Mainly clean up operations, if the return value is None or non-True, the exception in the with statement will be thrown up to the upper level, note that the exception in the with statement.
        return True

Test code main.py:

#! /usr/bin/env python
# -*- coding: utf-8 -*-
from my_context import MyContext

def test():
    with MyContext() as name:
        # raise Exception
        print(name)  # The return value of__________ is printed here.

if __name__ == "__main__":
    test()
In this way, the relevant information of with statement is introduced. I hope it will be helpful to you.
  • Communication can add QQ group: 397234385
  • Or QQ sweep code into groups:

qq group.jpg

Topics: Python Java