What is the WITH statement?
Python's with statement provides a very convenient is the dealing with the situation where you had to do a setup and tear Down-to-make something happen. A very good example for this is the situation where you want to gain a handler to a file, read data from the file and the Close the file handler. There are some tasks that may need to be set up beforehand to do cleanup work afterwards. For this scenario, Python's with statement provides a very convenient way to handle it. A good example is file handling, where you need to get a file handle, read the data from the file, and then close the file handle. Without the WITH statement, one would write something along the lines of: If you do not use the WITH statement, the code is as follows:
123 |
file = open ( "/tmp/foo.txt" ) data = file .read() file .close() |
There is annoying things here. First, you end up forgetting to close the file handler. The second is what to handle exceptions, may occur once the file handler have been obtained. One could write something like this to get around this: here are two questions. One is the possibility of forgetting to close the file handle, and the other is that the file read data is abnormal and no processing is done. The following is an enhanced version of handling exceptions:
12345 |
file = open ( ) try : Code class= "python spaces" > data = file .read () Code class= "python keyword" >finally : file .close () |
While this works well, it is unnecessarily verbose. This is where and is useful. The good thing about with apart from the better syntax is, it is very good handling exceptions. The above code would, when using with: Although this code works well, it is too verbose. This is the time for a show with a skill. In addition to having a more elegant syntax, with can also handle the exception generated by the context environment very well. The following is the code with the version:
12 |
with open ( "/tmp/foo.txt" ) as file : data = file .read() |
How does the with work?
While this might-like magic, the the-the-the-handles with are more clever than magic. The basic idea is, the statement after with have to evaluate an object, responds to a __enter__ () as well as a __ Exit__ () function. It looks magical, but not just magic, and Python's handling of with is smart. The basic idea is that the object with which the value is evaluated must have a __enter__ () method, a __exit__ () method. After the statement-follows with was evaluated, the __enter__ () function on the resulting object is called. The value returned by this function was assigned to the variable following as. After every statement in the block was evaluated, the __exit__ () function is called. Immediately after the statement that follows with is evaluated, the __enter__ () method of the returned object is called, and the return value of the method is assigned to the variable following the AS. The __exit__ () method of the previous return object is called when all code blocks following the with are executed. This can is demonstrated with the following example: The following examples specify how with works:
12345678910111213141516171819 |
#!/usr/bin/env python
# with_example01.py
class Sample:
def __enter__(
self
):
print "In __enter__()"
return "Foo"
def __exit__(
self
,
type
, value, trace):
print "In __exit__()"
def get_sample():
return Sample()
with get_sample() as sample:
print "sample:"
, sample
|
When executed, this'll result in: Run code, output as follows
1234 |
bash - 3.2 $ . / with_example01.py In __enter__() sample: Foo In __exit__() |
As can see, the __enter__ () function was executed the value returned by it-in this case "Foo" was assigned to sample T He body of the block is executed, thereby printing the value of the sample ie. "Foo" the __exit__ () function is called. What makes with really powerful are the fact that it can handle exceptions. You would has noticed the __exit__ () function for Sample takes three Arguments-val, type and trace. These is useful in exception handling. Let's see how it works by modifying the above example. As you can see, 1. The __enter__ () method is executed 2. The value returned by the __enter__ () method-In this case, "Foo", is assigned to the variable ' sample ' 3. Executes the code block and prints the variable "sample" with the value "Foo" 4. The __exit__ () method is called with the real power that it can handle exceptions. You may have noticed that the __exit__ method of the sample class has three parameters-Val, type, and trace. These parameters are quite useful in exception handling. Let's change the code to see how it works.
12345678910111213141516171819 |
#!/usr/bin/env python
# with_example02.py class Sample:
def __enter__(
self
):
return self
def __exit__(
self
,
type
, value, trace):
print "type:"
,
type
print "value:"
, value
print "trace:"
, trace
def do_something(
self
):
bar
= 1
/
0
return bar
+ 10
with Sample() as sample:
sample.do_something()
|
Notice how the example, instead of Get_sample (), with takes sample (). It does not matter, as long as the statement that follows with evaluates to a object that have an __enter__ () and __exit__ () functions. In this case, sample () 's __enter__ () returns the newly created instance of sample and that's what gets passed to Sample. In this example, the Get_sample () behind with is changed to sample (). This has nothing to do with the __enter__ () and __exit__ () methods as long as the object returned by the statement following the with is followed. In this example, the __enter__ () method of sample () returns the newly created sample object and assigns a value to the variable sample. When executed: After code execution:
12345678910 |
bash
-
3.2
$ .
/
with_example02.py
type
: <
type ‘exceptions.ZeroDivisionError‘
>
value: integer division
or modulo by zero
trace: <traceback
object at
0x1004a8128
>
Traceback (most recent call last):
File "./with_example02.py"
, line
19
,
in <module>
sample.do_something()
File "./with_example02.py"
, line
15
,
in do_something
bar
= 1
/
0
ZeroDivisionError: integer division
or modulo by zero
|
Essentially, if there is exceptions being thrown from anywhere inside the block, the __exit__ () function for the object I s called. As you can see, the type, value and the stack trace associated with the exception thrown are passed to this function. In this case, you can see that there is a Zerodivisionerror exception being thrown. People implementing libraries can write code that is clean up resources, close files etc. in their __exit__ () functions. In fact, the __exit__ () method is executed when any exception is thrown in the code block following the with. As the example shows, when an exception is thrown, the associated type,value and stack trace is passed to the __exit__ () method, so the thrown Zerodivisionerror exception is printed out. When you develop a library, clean up resources, close files, and so on, all in the __exit__ method. Thus, Python ' s a nifty construct, makes code a little less verbose and makes cleaning up during exceptions a B it easier. As a result, Python's with statement provides an effective mechanism for making the code more concise and for easier cleanup when the exception is generated. I have put the code examples given here on Github. The sample code can be found on GitHub.
Instructions for using with in Python