程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式師世界 >> 編程語言 >  >> 更多編程語言 >> Python

Explain extending Python timers with context manager

編輯:Python

Catalog

One Python Timer context manager

understand Python Context manager in

Understand and use contextlib

establish Python Timer context manager

Use Python Timer context manager

At the end

In this paper , We have learned hand in hand to teach you how to achieve a Python timer . In this paper , Yunduo Jun will understand what is Context manager   and Python Of  with sentence , And how to complete customization . Then extend  Timer  So that it can Used as context manager . Last , Use Timer How to simplify our own code as a context manager .

The first one we created above Python Timer class , Then gradually expand us  Timer  class , Its code is also relatively rich and powerful . We can't be satisfied with this , You still need some code from the template to use Timer

First , Instantiate the class

secondly , Call before the code block to be timed  .start()

Last , Call after the code block  .stop()

One Python Timer context manager

Python There is a unique structure , Used to call a function before and after a code block : Context manager .

understand Python Context manager in

Context managers have long been Python An important part of . from PEP 343 On 2005 In introducing , And for the first time in Python 2.5 To realize . have access to  with  Keyword identifies the context manager in the code :

with EXPRESSION as VARIABLE:    BLOCK

EXPRESSION  Are some that return to the context manager Python expression . First, the context manager is bound to the variable name  VARIABLE On ,BLOCK  Can be any conventional Python Code block . The context manager guarantees that the program is in  BLOCK  Before calling some code , stay  BLOCK  Call some other code after execution . Even though  BLOCK  Trigger exception , The latter will also be implemented .

The most common use of a context manager is to handle different resources , Such as file 、 Locks and database connections . The context manager is used to release and clean up resources after they are used . The following example demonstrates this only by printing lines containing colons  timer.py  Basic structure . Besides , It shows that in Python Common idioms for opening files in :

with open("timer.py") as fp:    print("".join(ln for ln in fp if ":" in ln))class TimerError(Exception):class Timer:    timers: ClassVar[Dict[str, float]] = {}    name: Optional[str] = None    text: str = "Elapsed time: {:0.4f} seconds"    logger: Optional[Callable[[str], None]] = print    _start_time: Optional[float] = field(default=None, init=False, repr=False)    def __post_init__(self) -> None:        if self.name is not None:    def start(self) -> None:        if self._start_time is not None:    def stop(self) -> float:        if self._start_time is None:        if self.logger:        if self.name:

Be careful , Use  open()  As context manager , The file pointer fp  Does not explicitly close , Can confirm  fp  Automatically closed :

fp.closed

True

In this example ,open("timer.py")  Is an expression that returns the context manager . The context manager is bound to a name  fp. Context manager in  print()  Valid during execution . This single line code block is in  fp  In the context of .

fp  What does context manager mean ?  Technically speaking , Namely  fp  Realized   Context Manager Protocol .Python There are many different protocols at the bottom of the language . You can think of a protocol as a contract that states what specific methods our code must implement .

The context manager protocol consists of two methods :

Called when the context associated with the context manager is entered  .__enter__().

Called when exiting the context associated with the context manager  .__exit__().

let me put it another way , Create your own context manager , You need to write an implementation  .__enter__()  and  .__exit__()  Class . try  Hello, World! The context manager example :

# studio.pyclass Studio:    def __init__(self, name):        self.name = name    def __enter__(self):        print(f" Hello  {self.name}")        return self    def __exit__(self, exc_type, exc_value, exc_tb):        print(f" See you later , {self.name}")

Studio It's a context manager , It implements the context manager protocol , Use as follows :

from studio import Studiowith Studio(" Cloud King "):    print(" Busy  ...")

Hello Cloud King
Busy ...
See you later , Cloud King

First , Be careful  .__enter__()  How to be called before doing something , and  .__exit__()  Is called after doing something . In the example , There is no reference to the context manager , Therefore, it is not necessary to use  as  Name the context manager .

Next , Be careful  self.__enter__()  The return value of is restricted by  as  constraint . When creating the context manager , Usually want from  .__enter__()  return  self . The return value can be used as follows :

from greeter import Greeterwith Greeter(" Cloud King ") as grt:  print(f"{grt.name}  Busy  ...")

Hello Cloud King
Cloud King Busy ...
See you later , Cloud King

Writing  __exit__  Function time , Something to pay attention to , It must have these three parameters :

exc_type: Exception types

exc_val: outliers

exc_tb: Abnormal error stack information

These three parameters are used for error handling in the context manager , They use  sys.exc_info()  The return value of returns . When the main logic code does not report an exception , All three parameters will be None.

If an exception occurs while executing the block , Then the code will use the exception type 、 Exception instances and backtracking objects ( namely exc_typeexc_value and exc_tb) call  .__exit__() . Usually , These are ignored in the context manager , Call before throwing an exception  .__exit__()

from greeter import Greeterwith Greeter(" Cloud King ") as grt:    print(f"{grt.age} does not exist")

Hello Cloud King
See you later , Cloud King
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
AttributeError: 'Greeter' object has no attribute 'age'

You can see , Even if there are errors in the code , Still printed  " See you later , Cloud King ".

Understand and use contextlib

Now we have a preliminary understanding of what a context manager is and how to create our own context manager . In the example above , We just want to build a context manager , But wrote a class . If you just want to implement a simple function , Writing a class is a little too complicated . Now , We just want to , If only one function can be written to implement the context manager .

This point Python I've thought about it for a long time . It provides us with a decorator , You just need to implement the function content according to its code Protocol , You can turn this function object into a context manager .

We are in accordance with the contextlib To implement a context manager , To be more intuitive, let's change the use case , Create an open file that we are familiar with (with open) Context manager for .

import [email protected] open_func(file_name):    # __enter__ Method     print('open file:', file_name, 'in __enter__')    file_handler = open(file_name, 'r')    # 【 a key 】:yield    yield file_handler    # __exit__ Method     print('close file:', file_name, 'in __exit__')    file_handler.close()    returnwith open_func('test.txt') as file_in:    for line in file_in:        print(line)

In the decorated function , Must be a generator ( with yield), and  yield  Previous code , Equivalent to __enter__ Contents of Li .yield  Later code , Equivalent to __exit__  Contents of Li .

The above code can only achieve the first purpose of the context manager ( Management resources ), Can not achieve the second purpose ( Handling exceptions ).

If you want to handle exceptions , You can change it to the following .

import [email protected] open_func(file_name):    # __enter__ Method     print('open file:', file_name, 'in __enter__')    file_handler = open(file_name, 'r')    try:        yield file_handler    except Exception as exc:        # deal with exception        print('the exception was thrown')    finally:        print('close file:', file_name, 'in __exit__')        file_handler.close()        returnwith open_func('test.txt') as file_in:    for line in file_in:        1/0        print(line)

Python In the standard library  contextlib Includes a convenient way to define a new context manager , And can be used to close objects 、 Out of the box context managers that suppress errors or even do nothing !

establish Python Timer context manager

After understanding the general working mode of the context manager , Want to know how they help with temporal code ? Suppose if you could Run some functions before and after the code block , Then it can be simplified Python How the timer works . Actually , The context manager can automatically call... Explicitly for timing  .start()  and .stop().

Again , Must let Timer Working as a context manager , It needs to comply with the context manager protocol , let me put it another way , It has to be implemented  .__enter__()  and  .__exit__()  Method to start and stop Python timer . As you can see from the current code , All the necessary functions are already available , So just add the following methods to the  Timer  Class :

# [email protected] Timer:    #  Other code remains the same     def __enter__(self):        """Start a new timer as a context manager"""        self.start()        return self    def __exit__(self, *exc_info):        """Stop the context manager timer"""        self.stop()

Timer Now it is a context manager . An important part of the implementation is when entering the context , .__enter__()  call  .start()  start-up Python timer , And when the code leaves the context , .__exit__()  Use  .stop()  stop it Python timer .

from timer import Timerimport timewith Timer():    time.sleep(0.7)

Elapsed time: 0.7012 seconds

Notice two more subtle details here :

.__enter__()  return  self,Timer  example , It allows users to use  as  take  Timer  Instance bound to variable . for example , Use  with Timer() as t:  Will create points to  Timer  Object's variables  t.

.__exit__()  Three parameters are required , It contains information about any exceptions that occur during context execution . In the code , These parameters are packaged in a file named  exc_info  In the tuple of , Then ignored , here Timer No exception handling will be attempted .

In this case, no exceptions are handled . A big feature of the context manager is , Exit regardless of the context , Will ensure that .__exit__(). In the following example , Create divide by zero formula to simulate exception view code function :

from timer import Timerwith Timer():    for num in range(-3, 3):        print(f"1 / {num} = {1 / num:.3f}")

1 / -3 = -0.333
1 / -2 = -0.500
1 / -1 = -1.000
Elapsed time: 0.0001 seconds
Traceback (most recent call last):
  File "<stdin>", line 3, in <module>
ZeroDivisionError: division by zero

Be careful , Even if the code throws an exception ,Timer  The elapsed time will also be printed .

Use Python Timer context manager

Now we will learn how to use  Timer  Context manager to time " Download data " Program . Think back to how you used Timer Of :

# download_data.pyimport requestsfrom timer import Timerdef main():    t = Timer()    t.start()    source_url = 'https://cloud.tsinghua.edu.cn/d/e1ccfff39ad541908bae/files/?p=%2Fall_six_datasets.zip&dl=1'    headers = {'User-Agent': 'Mozilla/5.0'}    res = requests.get(source_url, headers=headers)     t.stop()    with open('dataset/datasets.zip', 'wb') as f:        f.write(res.content)if __name__ == "__main__":    main()

We are right now  requests.get()  Call to time monitor . Using the context manager, you can make your code shorter 、 It's simpler 、 Easier to read

# download_data.pyimport requestsfrom timer import Timerdef main():    source_url = 'https://cloud.tsinghua.edu.cn/d/e1ccfff39ad541908bae/files/?p=%2Fall_six_datasets.zip&dl=1'    headers = {'User-Agent': 'Mozilla/5.0'}    with Timer():        res = requests.get(source_url, headers=headers)    with open('dataset/datasets.zip', 'wb') as f:        f.write(res.content)if __name__ == "__main__":    main()

This code is actually the same as the code above . The main difference is that there are no independent variables defined t, There is nothing superfluous in the namespace .

At the end

Add context manager functionality to Python The timer class has several advantages :

Time saving and labor saving : Only one extra line of code is required to time the execution of the code block .

High readability : Calling the context manager is readable , You can more clearly visualize the code block you are timing .

Use  Timer  As a context manager, it is almost used directly  .start()  and  .stop()  Just as flexible , It also has less boilerplate code .

The above is a detailed explanation of using the context manager extension Python Details of the timer , More about Python Context manager For information about timers, please pay attention to other relevant articles on the software development network !



  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式師世界 All Rights Reserved