Understand Python's with ____________ as... grammar

Keywords: Python

First of all, a common problem is to open the file:

try:
    f= open('xxx')
    do something
except:
    do something
finally:
    f.close()


In fact, I have seen it on the Internet more than once, which is wrong.
First of all, the following are correct:

try:
    f= open('xxx')
except:
    print'fail to open'
    exit(-1)
try:
    do something
except:
    do something
finally:
    f.close()


It's troublesome, isn't it? But that's the right way to write it.
The reason why we write final is to prevent the program from throwing exceptions and finally not closing the file, but there is a prerequisite for closing the file that the file has been opened.
In the first error code, if an exception occurs when f=open('xxx'), such as when a file does not exist, it immediately becomes clear that executing f.close() is meaningless. The corrected solution is the second piece of code.

Well, turn around and start discussing with grammar.

Let's start with the following question: try-final grammatical structure:

setthings up
try:
    do something
finally:
    tear things down


This is a common structure, such as file opening, set things up for f=open('xxx'), tear Things down means f.close(). For example, multithreaded locks, resource requests, eventually have a release requirement. Try... The final structure guarantees that the tear things down section will always be executed, even if the above do Some things have not been fully implemented.

If this structure is often used, we can first adopt a more elegant approach to encapsulation!

defcontrolled_execution(callback):
    setthings up
    try:
        callback(thing)
    finally:
        tear things down
 
defmy_function(thing):
    do something
 
controlled_execution(my_function)


Encapsulation is a good way to support code reuse, but it's dirty, especially when there are changes to some local variables in do something.

Another way is to use the generator, but only need to generate data once, we use the for-in structure to call him:

defcontrolled_execution():
    setthings up
    try:
        yieldthing
    finally:
        tear things down
         
forthing incontrolled_execution():
    do something with thing


Because there is only one thing to think, the yield statement only needs to be executed once. Of course, from the point of view of code readability, that is, elegance, it's terrible. We still use the for loop when we make sure that the for loop is executed only once. This code shows people who don't know how hard it is to understand what the loop is here.

The final python-dev team solution. (After python 2.5, the grammar of with expressions has been added)

classcontrolled_execution:
    def__enter__(self):
        setthings up
        returnthing
    def__exit__(self,type, value, traceback):
        tear things down
         
with controlled_execution() as thing:
        do something


Here, python uses the with-as grammar. When python executes this sentence, it calls the _enter_ function and passes the value of the function return to the variable specified after as. After that, python executes the following do something block. Finally, no matter what exception occurs in the statement block, it executes _exit_ when it leaves.
In addition, _exit_ can be used for monitoring and processing of anomalies besides tear things down, paying attention to the latter parameters. To skip an exception, simply return the function True. The following sample code skips all TypeError and throws other exceptions normally.

def__exit__(self,type, value, traceback):
    returnisinstance(value, TypeError)

In Python 2.5 and beyond, the file object has written _enter_ and _exit_ functions. We can test this by:

>>> f= open("x.txt")
>>> f
<openfile 'x.txt', mode 'r'at 0x00AE82F0>
>>> f.__enter__()
<openfile 'x.txt', mode 'r'at 0x00AE82F0>
>>> f.read(1)
'X'
>>> f.__exit__(None,None,None)
>>> f.read(1)
Traceback (most recent call last):
    File"<stdin>", line1,in <module>
ValueError: I/O operation on closedfile

Afterwards, if we want to open the file and ensure that it is finally closed, we just need to do this:

withopen("x.txt") as f:
    data= f.read()
    do something with data

If there are more than one item, we can write as follows:

withopen("x.txt") as f1,open('xxx.txt') as f2:
    do something with f1,f2

As mentioned above, the _exit_ function can handle some exceptions. If we don't handle exceptions in this function, it will throw them normally. At this time, we can write as follows (python version 2.7 and above, the previous version refers to the library function contextlib.nested):

try:
    withopen("a.txt" ) as f :
        do something
exceptxxxError:
    do something about exception

In short, with-as expressions greatly simplify the work of writing finally each time, which is of great help to maintain the elegance of the code.

Posted by lee20 on Sun, 24 Mar 2019 04:39:28 -0700