author | Cloud King
source | data STUDIO
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 .
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.py
class 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 Studio
with 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 Greeter
with 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_type
、exc_value
and exc_tb
) call .__exit__()
. Usually , These are ignored in the context manager , Call before throwing an exception .__exit__()
:
from greeter import Greeter
with 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 "
.
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 contextlib
@contextlib.contextmanager
def 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()
return
with 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 contextlib
@contextlib.contextmanager
def 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()
return
with 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 !
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 :
# timer.py
@dataclass
class 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 Timer
import time
with 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 Timer
with 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 .
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.py
import requests
from timer import Timer
def 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.py
import requests
from timer import Timer
def 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 . In the next article in this series , Yunduo Jun will learn how to Timer Also used for Decorator , And used in code , Thus, it is easier to monitor the complete running process of the code , Let's look forward to !
Looking back
NLP Exploration and practice of class problem modeling scheme
Python Common encryption algorithms in crawlers !
2D Transformation 3D, Look at NVIDIA's AI“ new ” magic !
How to use Python Realize the security system of the scenic spot ?
Share
Point collection
A little bit of praise
Click to see