The with statement was introduced in PEP 343. This PEP also introduced the new term “context manager” and defined what the term means.
In short, a "context manager" is an object that has special functions of the .__enter__() and .__exit__() method. The with statement ensures that the .__enter__() method is called to configure the code block indented in the with statement, and also ensures that the .__exit__() method function is called when the code block exits (no matter how the block exits, for example, if the code throws an exception, .__exit__() will still be called).
http://www.python.org/dev/peps/pep-0343/
http://docs.python.org/2/reference/datamodel.html?highlight=context%20manager#with-statement-context-managers
The with statement is now the preferred way to handle any task that has a well-defined set-up and shutdown. Work with a file, for example:
with open(file_name) as f:
You know that the file will be closed when you are done.
Another great example is resource locking:
with acquire_lock(my_lock):
You know that the code will not work until you get the lock, and as soon as the code is executed, the lock will be released. I don't often do multithreaded coding in Python, but when I did, this statement made sure that the lock was always issued even in the face of an exception.
PS I did an Internet search on the Internet for examples of context managers, and I found this excellent one: a context manager that executes a Python block in a specific directory.
http://ralsina.me/weblog/posts/BB963.html
EDIT:
The runtime context is the environment configured by calling .__enter__() and discarded by calling .__exit__() . In my example of getting a lock, a code block works in the context of having a lock. In the example of reading a file, a block of code is launched in the context of an open file.
There is no secret magic inside Python for this. There is no special coverage, no internal stack, and nothing special about the parser. You just write two method functions, .__enter__() and .__exit__() , and Python calls them at specific points for your with statement.
Take another look at this section from PEP:
Remember that PEP 310 offers roughly this syntax (part of VAR = "optional):
with VAR = EXPR: BLOCK
which roughly corresponds to this:
VAR = EXPR VAR.__enter__() try: BLOCK finally: VAR.__exit__()
In both examples, BLOCK is a block of code that runs in a specific execution context, which is configured by calling VAR.__enter__() and is reset to VAR.__exit__() .
There are two main benefits to the with statement and how to configure it.
A more specific advantage is that it is “syntactic sugar”. I would rather write a two-line with statement than a six-line sequence of statements; it's easier two write shorter, it looks prettier and easier to understand, and easier to get right. Six lines versus two means more chance of damaging the situation. (And before the with statement, I usually neglected wrapping the file I / O in the try block, sometimes I did it. Now I always use with and always get exception handling.)
The more abstract advantage is that it gives us a new way to think about developing our programs. Raymond Hettinger, in a conversation with PyCon 2013, said this: when we write programs, we look for common parts that we can take into account in functions. If we have a code like this:
A B C D E F B C D G
we can easily make a function:
def BCD(): B C D A BCD() E F BCD() G
But we never had a really clean way to do this with install / disable. When we have a lot of code:
A BCD() E A XYZ() E A PDQ() E
Now we can define the context manager and rewrite it above:
with contextA: BCD() with contextA: XYZ() with contextA: PDQ()
So, now we can think about our programs and look for installation / breaks that can be abstracted into the "context manager". Raymond Hettinger revealed several new recipes for the "context manager" that he invented (and I torment my brain, trying to recall an example or two for you).
EDIT: Alright, I just remembered. Raymond Hettinger showed a recipe that will be built into Python 3.4 to use the with statement to ignore an exception in a block. See here: fooobar.com/questions/14098 / ...
PS I did my best to make it clear what he was saying ... if I made any mistake or distorted something, it was on me, not on him. (And he sometimes publishes StackOverflow, so he can just see it and fix me if I messed up something.)
EDIT: You updated the question with lots of text. I will also answer it specifically.
is that what Basley means when he talks about the "run-time context" that f is limited only within the block and loses all significance outside the block? Why does he say that statements are "executed within the context of the runtime environment" ??? Does this look like an "eval"?
Actually, f not limited only inside the block. When you bind a name using the as keyword in a with statement, the name remains bound after the block.
The "runtime" is an informal concept, which means "the state configured by the method function call .__enter__() and torn down by the method function call .__exit__() ". Again, I think the best example is getting a lock before running the code. A block of code works in the "context" of having a lock.
I understand that open returns an object that is "not ... assigned to var" ?? Why is it not assigned to var? What does Basley mean by making such an expression?
Well, suppose we have an object, let's call it k . k implements a "context manager", which means that it has the functions of the k.__enter__() and k.__exit__() methods. Now we do this:
with k as x:
What David Basley wants you to know that x will not necessarily be attached to k . x will be tied to some kind of return k.__enter__() . k.__enter__() may return a reference to k itself, but may also return something else. In this case:
with open(some_file) as f:
The open() call returns an open file object that acts as a context manager, and its method function .__enter__() really returns a reference to itself.
I think most context managers return a link to themselves. Since this is an object, it can have any number of member variables, so it can return any number of values in a convenient way. But it is not required.
For example, there might be a context manager that starts a daemon running in the .__enter__() function and returns the daemon process ID number from the .__enter__() function. Then the .__exit__() function will disable the daemon. Using:
with start_daemon("parrot") as pid: print("Parrot daemon running as PID {}".format(pid)) daemon = lookup_daemon_by_pid(pid) daemon.send_message("test")
But you could also return a context manager object with any values that you need to pin inside:
with start_daemon("parrot") as daemon: print("Parrot daemon running as PID {}".format(daemon.pid)) daemon.send_message("test")
If we need the PID of the daemon, we can simply put it in the .pid element of the object. And later, if we need something else, we can just fix it there.