Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What is the essence and usage of Python context manager

2025-01-19 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

Today, I will talk to you about the nature and usage of Python context manager, which may not be well understood by many people. in order to make you understand better, the editor has summarized the following contents. I hope you can get something from this article.

1. What is the context manager?

For example, when you write Python code, you often put a series of actions in a statement block:

When a condition is true-execute this statement block

Execute this block of statements when a condition is true-loop

Sometimes we need to maintain a certain state when the program is running in the statement block and end it after leaving the statement block.

So, in fact, the task of the context manager is to prepare the code block before execution and clean up the code block after execution.

The context manager is a feature added to Python2.5 to make your code more readable and error-free. Next, let's see how to use it.

two。 How do I use the context manager?

Look at the way code is learned. Let's see how we usually open a file and write "Hello World".

Filename = 'my_file.txt' mode =' w' # Mode that allows to write to the file writer = open (filename, mode) writer.write ('Hello') writer.write ('World') writer.close ()

Lines 1-2, we specify the file name and how to open it (write).

Line 3, open the file, line 4-5 write "Hello world", and line 6 close the file.

That's fine, so why do you need a context manager? But we missed a small but important detail: what if we didn't have a chance to get to line 6 to close the file?

For example, the disk is full, so we throw an exception when we try to write to the file on line 4, while line 6 has no chance to execute at all.

Of course, we can use try-finally statement blocks to wrap:

Writer = open (filename, mode) try: writer.write ('Hello') writer.write ('World') finally: writer.close ()

The code in the finally statement block executes no matter what happens in the try statement block. So you can guarantee that the file will be closed. Is there a problem with this? Of course not, but when we do something more complicated than writing "Hello world", the try-finally statement becomes ugly. For example, if we want to open two files, one to read and one to write, and copy between the two files, then we can ensure that both can be closed at the same time through the with statement.

OK, let's break things down:

First, create a file variable named "writer".

Then, do something on writer.

*, close writer.

Isn't that much more elegant?

With open (filename, mode) as writer: writer.write ('Hello') writer.write ('World')

Let's go a little further. "with" is a new keyword and always comes with the context manager. "open (filename, mode)" has appeared in the previous code. "as" is another keyword that refers to what is returned from the "open" function and assigns it to a new variable. "writer" is a new variable name.

2-3 lines, indent to open a new block of code. In this code block, we can do anything with writer. So we use the "open" context manager, which ensures that our code is both elegant and secure. It has accomplished the task of try-finally excellently.

The open function can be used both as a simple function and as a context manager. This is because the open function returns a file type (file type) variable that implements the write method we used earlier, but you have to implement some special methods if you want to be a context manager, which I'll cover in the next section.

3. Custom context Manager

Let's write a "open" context manager.

To implement the context manager, two methods must be implemented-one is responsible for the preparation of entering the statement block, and the other is responsible for the aftermath of leaving the statement block. At the same time, we need two parameters: the file name and the opening method.

The Python class contains two special methods named _ _ enter__ and _ _ exit__ (with double underscores as prefixes and suffixes).

When an object is used as a context manager:

The _ _ enter__ method will be called before entering the code block.

The _ _ exit__ method is called after leaving the code block (even if an exception is encountered in the code block).

The following is an example of a context manager that prints when entering and leaving a block of code, respectively.

Class PypixContextManagerDemo: def _ _ enter__ (self): print 'Entering the block' def _ _ exit__ (self, * unused): print' Exiting the block' with PypixContextManagerDemo (): print'In the block' # Output: # Entering the block # In the block # Exiting the block

Pay attention to something:

No parameters were passed.

The keyword "as" is not used here.

We will discuss the parameter setting of the _ _ exit__ method later.

How do we pass parameters to a class? In fact, the _ _ init__ method can be used in any class, and here we will rewrite it to receive two necessary parameters (filename, mode).

When we enter the statement block, we will use the open function, as in the * * example. When we leave the statement block, we close everything that is opened in the _ _ enter__ function.

Here is our code:

Class PypixOpen: def _ init__ (self, filename, mode): self.filename = filename self.mode = mode def _ enter__ (self): self.openedFile = open (self.filename, self.mode) return self.openedFile def _ exit__ (self, * unused): self.openedFile.close () with PypixOpen (filename) Mode) as writer: writer.write ("Hello World from our new Context Manager!")

Let's take a look at the changes:

Lines 3-5, receiving two parameters through _ _ init__.

Line 7-9, open the file and return.

Line 12, close the file when you leave the statement block.

Lines 14-15, mimicking open using our own context manager.

In addition, there are some things that need to be emphasized:

How to handle exceptions

We completely ignored the problems that might occur within the statement block.

If an exception occurs inside the statement block, the _ _ exit__ method is called and the exception is re-thrown (re-raised). When dealing with file writes, you certainly don't want to hide these exceptions most of the time, so it's okay. For exceptions that you do not want to rethrow, we can simply let the _ _ exit__ method return True to ignore all exceptions that occur in the statement block (which is not wise in most cases).

We can learn more about the exception when it occurs. A complete _ _ exit__ function signature should look like this:

Def _ _ exit__ (self, exc_type, exc_val, exc_tb)

In this way, the _ _ exit__ function can get all the information about the exception (exception type, exception value, and exception tracking information), which will assist the exception handling operation. I won't discuss how to write exception handling in detail here. The following is an example that is only responsible for throwing SyntaxErrors exceptions.

Class RaiseOnlyIfSyntaxError: def _ enter__ (self): pass def _ exit__ (self, exc_type, exc_val, exc_tb): return SyntaxError! = exc_type4. Talk about something about context library (contextlib)

Contextlib is a Python module that provides an easier-to-use context manager.

Contextlib.closing

Suppose we have a create database function that returns a database object and closes related resources (database connection sessions, etc.) after use.

We can handle it as usual or through the context manager:

With contextlib.closing (CreateDatabase ()) as database: database.query ()

The contextlib.closing method invokes the database shutdown method after the statement block ends.

Contextlib.nested

Another very cool feature can effectively help us reduce nesting:

Suppose we have two files, one to read and the other to write, which need to be copied.

The following are not recommended:

With open ('toReadFile', 'r') as reader: with open (' toWriteFile',') as writer: writer.writer (reader.read ())

It can be simplified through contextlib.nested:

With contextlib.nested (open ('fileToRead.txt', 'r'), open (' fileToWrite.txt', 'w')) as (reader, writer): writer.write (reader.read ())

In Python2.7, this writing is replaced by a new syntax:

With open ('fileToRead.txt', 'r') as reader,\ open (' fileToWrite.txt',') as writer: writer.write (reader.read ()) contextlib.contextmanager

For advanced Python players, any function that can be divided into two parts by yield keywords can be implemented through the context manager decorated by the decorator. Anything before yield can be seen as an operation before the code block is executed, and any operation after yield can be placed in the exit function.

Let me give you an example of a thread lock:

The locking mechanism ensures that two pieces of code will not interfere with each other when executed at the same time. For example, if we have two pieces of code executing in parallel to write a file at the same time, we will get an error file that mixes two inputs. But if we can have a lock, and any code that wants to write a file must first acquire the lock, then things will be easy. If you want to know more about concurrent programming, please refer to the relevant literature.

Here is an example of a thread-safe write function:

Import threading lock = threading.Lock () def safeWriteToFile (openedFile, content): lock.acquire () openedFile.write (content) lock.release ()

Next, let's implement it using the context manager, recalling the previous analysis of yield and contextlib:

Contextlib.contextmanager def loudLock (): print 'Locking' lock.acquire () yield print' Releasing' lock.release () with loudLock (): print 'Lock is locked:% s'% lock.locked () print 'Doing something that needs locking' # Output: # Locking # Lock is locked: True # Doing something that needs locking # Releasing

In particular, this is not the way to write abnormal security (exception safe). If you want to keep the exception safe, use the try statement on yield. Fortunately, threading. Lock is already a context manager, so we just need to simply:

@ contextlib.contextmanager def loudLock (): print 'Locking' with lock: yield print' Releasing'

Because threading.lock returns False through the _ _ exit__ function when an exception occurs, this will be re-thrown when yield is called. In this case, the lock will be released, but the call to "print 'Releasing'" will not be executed unless we rewrite the try-finally.

If you want to use the "as" keyword in the context manager, use yield to return the value you need, which will be assigned to the new variable through the as keyword.

After reading the above, do you have any further understanding of the nature and usage of the Python context manager? If you want to know more knowledge or related content, please follow the industry information channel, thank you for your support.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report