What is a runtime?

(Edited for clarity)

I am reading a Python book (Python Essential Reference by Beazley) and it says:

The with statement allows you to execute a series of statements inside which is controlled by an object that serves as a context manager.

Here is an example:

 with open("debuglog","a") as f: f.write("Debugging\n") statements f.write("Done\n") 

He goes on to say:

The obj operator accepts optional as a var specifier. If specified, the value returned by obj._ enter _ () is placed in var. It is important to emphasize that obj is not necessarily the value assigned to var.

I understand the mechanics of what it does with the keyword : the file object is returned open , and this object is accessible via f inside the body of the block. I also understand that type () and eventually exit () is called.

But what is runtime context? A few low-level details would be good - or, for example, in C. Can anyone clarify what a "context" is and how it can relate to other languages ​​(C, C ++). My understanding of context was the environment, for example: the Bash shell executes ls in the context of all shell variables (env). With the keyword with - yes f is available for the block body, but is it not just browsing? For example: for x in y: here, x is not within the block and stores the value outside the block - is that what Beazley means when it says “execution context”, that f only spreads inside the block and loses all significance outside the block? Why does he say that the statements “execute inside the runtime context” ??? Does this look like an "eval"?

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?

+6
source share
2 answers

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: # do something with file 

You know that the file will be closed when you are done.

Another great example is resource locking:

 with acquire_lock(my_lock): # do something 

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: # do something 

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: # do something 

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.

+7
source

In the context, given the fact that the __enter__ method is called upon entry, and the specified var set to return __enter__ .

In most cases, this is the object that was previously processed - in the case of a file - this, but, for example, in the database, and not in the connection object, returns the cursor object.

The sample file can be continued as follows:

 f1 = open("debuglog","a") with f1 as f2: print f1 is f2 

which will print True , as here, the file object is returned by __enter__ . (From his point of view, self .)

The database works like

 d = connect(...) with d as c: print d is c # False print d, c 

Here d and c completely different: d is the database connection, c is the cursor used for one transaction.

The with clause ends with a call to __exit__() , which is given the execution status of the clause — either success or failure. In this case, the __exit__() method may act accordingly.

In the example file, the file is closed regardless of whether there was an error or not.

In the database example, a transaction usually completes successfully and rolls back when it fails.

The context manager is designed to easily initialize and clean things like these files, databases, etc.

There is no direct correspondence in C or C ++ that I know of.

C does not know the concept of exception, so no one can be caught in __exit__() . C ++ knows the exceptions, and there seem to be ways to do soo (see comments below).

+3
source

Source: https://habr.com/ru/post/956926/


All Articles