国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

如何用上下文管理器擴展 Python 計時器

開發 前端
本文中,云朵君將和大家一起了解什么是上下文管理器 和 Python 的 with 語句,以及如何完成自定義。然后擴展 Timer 以便它也可以用作上下文管理器。最后,使用 Timer 作為上下文管理器如何簡化我們自己的代碼。

上文中我們創建的第一個 Python 計時器類,然后逐步擴展我們 Timer 類,其代碼也是較為豐富強大。我們不能滿足于此,仍然需要模板一些代碼來使用Timer:

  • 首先,實例化類
  • 其次,在要計時的代碼塊之前調用.start()
  • 最后,在代碼塊之后調用.stop()

一個 Python 定時器上下文管理器

Python 有一個獨特的構造,用于在代碼塊之前和之后調用函數:上下文管理器。

了解 Python 中的上下文管理器

上下文管理器長期以來一直是 Python 中重要的一部分。由 PEP 343 于 2005 年引入,并首次在 Python 2.5 中實現。可以使用 with 關鍵字識別代碼中的上下文管理器:

with EXPRESSION as VARIABLE:
BLOCK

EXPRESSION 是一些返回上下文管理器的 Python 表達式。首先上下文管理器綁定到變量名 VARIABLE上,BLOCK 可以是任何常規的 Python 代碼塊。上下文管理器保證程序在 BLOCK 之前調用一些代碼,在 BLOCK 執行之后調用一些其他代碼。這樣即使 BLOCK 引發異常,后者也是會照樣執行。

上下文管理器最常見的用途是處理不同的資源,如文件、鎖和數據庫連接等。上下文管理器用于使用資源后釋放和清理資源。以下示例僅通過打印包含冒號的行來演示 timer.py 的基本結構。此外,它展示了在 Python 中打開文件的常用習語:

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:

注意,使用 open() 作為上下文管理器,文件指針fp 不會顯式關閉,可以確認 fp 已自動關閉:

fp.closed
True

在此示例中,open("timer.py") 是一個返回上下文管理器的表達式。該上下文管理器綁定到名稱 fp。上下文管理器在 print() 執行期間有效。這個單行代碼塊在 fp 的上下文中執行。

fp 是上下文管理器是什么意思? 從技術上講,就是 fp 實現了 上下文管理器協議。Python 語言底層有許多不同的協議??梢詫f議視為說明我們代碼必須實現哪些特定方法的合同。

上下文管理器協議由兩種方法組成:

  1. 進入與上下文管理器相關的上下文時調用.__enter__()。
  2. 退出與上下文管理器相關的上下文時調用.__exit__()。

換句話說,要自己創建上下文管理器,需要編寫一個實現 .__enter__() 和 .__exit__() 的類。試試 Hello, World!上下文管理器示例:

# studio.py
class Studio:
def __init__(self, name):
self.name = name

def __enter__(self):
print(f"你好 {self.name}")
return self

def __exit__(self, exc_type, exc_value, exc_tb):
print(f"一會兒見, {self.name}")

Studio是一個上下文管理器,它實現了上下文管理器協議,使用如下:

from studio import Studio
with Studio("云朵君"):
print("正在忙 ...")
你好 云朵君
正在忙 ...
一會兒見, 云朵君

首先,注意 .__enter__() 在做事之前是如何被調用的,而 .__exit__() 是在做事之后被調用的。該示例中,沒有引用上下文管理器,因此不需要使用 as 為上下文管理器命名。

接下來,注意 self.__enter__() 的返回值受 as 約束。創建上下文管理器時,通常希望從 .__enter__() 返回 self 。可以按如下方式使用該返回值:

from greeter import Greeter
with Greeter("云朵君") as grt:
print(f"{grt.name} 正在忙 ...")
你好 云朵君
云朵君 正在忙 ...
一會兒見, 云朵君

在寫 __exit__ 函數時,需要注意的事,它必須要有這三個參數:

  • exc_type:異常類型
  • exc_val:異常值
  • exc_tb:異常的錯誤棧信息

這三個參數用于上下文管理器中的錯誤處理,它們以 sys.exc_info() 的返回值返回。當主邏輯代碼沒有報異常時,這三個參數將都為None。

如果在執行塊時發生異常,那么代碼將使用異常類型、異常實例和回溯對象(即exc_type、exc_value和exc_tb)調用 .__exit__() 。通常情況下,這些在上下文管理器中會被忽略,而在引發異常之前調用 .__exit__():

from greeter import Greeter
with Greeter("云朵君") as grt:
print(f"{grt.age} does not exist")
你好 云朵君
一會兒見, 云朵君
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
AttributeError: 'Greeter' object has no attribute 'age'

可以看到,即使代碼中有錯誤,還是照樣打印了 "一會兒見, 云朵君"。

理解并使用 contextlib

現在我們初步了解了上下文管理器是什么以及如何創建自己的上下文管理器。在上面的例子中,我們只是為了構建一個上下文管理器,卻寫了一個類。如果只是要實現一個簡單的功能,寫一個類未免有點過于繁雜。這時候,我們就想,如果只寫一個函數就可以實現上下文管理器就好了。

這個點Python早就想到了。它給我們提供了一個裝飾器,你只要按照它的代碼協議來實現函數內容,就可以將這個函數對象變成一個上下文管理器。

我們按照 contextlib 的協議來自己實現一個上下文管理器,為了更加直觀我們換個用例,創建一個我們常用且熟悉的打開文件(with open)的上下文管理器。

import contextlib

@contextlib.contextmanager
def open_func(file_name):
# __enter__方法
print('open file:', file_name, 'in __enter__')
file_handler = open(file_name, 'r')

# 【重點】:yield
yield file_handler

# __exit__方法
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)

在被裝飾函數里,必須是一個生成器(帶有yield),而 yield 之前的代碼,就相當于__enter__里的內容。yield 之后的代碼,就相當于__exit__ 里的內容。

上面這段代碼只能實現上下文管理器的第一個目的(管理資源),并不能實現第二個目的(處理異常)。

如果要處理異常,可以改成下面這個樣子。

import contextlib

@contextlib.contextmanager
def open_func(file_name):
# __enter__方法
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 標準庫中的 contextlib包括定義新上下文管理器的便捷方法,以及可用于關閉對象、抑制錯誤甚至什么都不做的現成上下文管理器!

創建 Python 計時器上下文管理器

了解了上下文管理器的一般工作方式后,要想知道它們是如何幫助處理時序代碼呢?假設如果可以在代碼塊之前和之后運行某些函數,那么就可以簡化 Python 計時器的工作方式。其實,上下文管理器可以自動為計時時顯式調用 .start() 和.stop()。

同樣,要讓 Timer 作為上下文管理器工作,它需要遵守上下文管理器協議,換句話說,它必須實現 .__enter__() 和 .__exit__() 方法來啟動和停止 Python 計時器。從目前的代碼中可以看出,所有必要的功能其實都已經可用,因此只需將以下方法添加到之前編寫的的 Timer 類中即可:

# timer.py
@dataclass
class Timer:
# 其他代碼保持不變

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 現在就是一個上下文管理器。實現的重要部分是在進入上下文時, .__enter__() 調用 .start() 啟動 Python 計時器,而在代碼離開上下文時, .__exit__() 使用 .stop() 停止 Python 計時器。

from timer import Timer
import time
with Timer():
time.sleep(0.7)
Elapsed time: 0.7012 seconds

此處注意兩個更微妙的細節:

  • .__enter__()? 返回self?,Timer 實例,它允許用戶使用as? 將Timer ?實例綁定到變量。例如,使用with Timer() as t:? 將創建指向Timer ?對象的變量t。
  • .__exit__()? 需要三個參數,其中包含有關上下文執行期間發生的任何異常的信息。代碼中,這些參數被打包到一個名為exc_info 的元組中,然后被忽略,此時 Timer 不會嘗試任何異常處理。

在這種情況下不會處理任何異常。上下文管理器的一大特點是,無論上下文如何退出,都會確保調用.__exit__()。在以下示例中,創建除零公式模擬異常查看代碼功能:

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

注意 ,即使代碼拋出異常,Timer 也會打印出經過的時間。

使用 Python 定時器上下文管理器

現在我們將一起學習如何使用 Timer 上下文管理器來計時 "下載數據" 程序。回想一下之前是如何使用 Timer 的:

# 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()

我們正在對 requests.get() 的調用進行記時監控。使用上下文管理器可以使代碼更短、更簡單、更易讀:

# 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()

此代碼實際上與上面的代碼相同。主要區別在于沒有定義無關變量t,在命名空間上無多余的東西。

寫在最后

將上下文管理器功能添加到 Python 計時器類有幾個優點:

  • 省時省力:只需要一行額外的代碼即可為代碼塊的執行計時。
  • 可讀性高:調用上下文管理器是可讀的,你可以更清楚地可視化你正在計時的代碼塊。

使用 Timer 作為上下文管理器幾乎與直接使用 .start() 和 .stop() 一樣靈活,同時它的樣板代碼更少。在該系列下一篇文章中,云朵君將和大家一起學習如何將 Timer 也用作裝飾器,并用于代碼中,從而更加容易地監控代碼完整運行過程,我們一起期待吧!

責任編輯:華軒 來源: 數據STUDIO
相關推薦

2025-06-06 08:00:00

上下文管理器Python開發

2014-04-04 10:27:00

Python上下文管理器

2022-11-03 08:29:32

編程管理器協議

2017-05-11 14:00:02

Flask請求上下文應用上下文

2023-11-16 08:46:27

上下文管理器Python

2022-10-31 15:34:30

python裝飾器內存泄漏

2024-03-14 08:11:45

模型RoPELlama

2024-11-14 09:00:00

Python上下文管理器

2022-06-30 16:10:26

Python計時器裝飾器

2022-09-14 13:13:51

JavaScript上下文

2023-12-10 13:37:23

Python編程上下文管理

2020-10-21 09:11:52

Spring Boot源碼分析代碼

2022-09-15 08:01:14

繼承基礎設施基礎服務

2021-11-03 16:41:30

Windows 11操作系統微軟

2023-07-11 10:02:23

2011-05-31 16:50:35

Android 線程

2012-05-08 13:58:37

SharePoint

2025-11-25 09:19:40

2024-02-21 19:56:48

??filterA并發計算

2025-10-14 01:55:00

AI應用上下文工程機器人
點贊
收藏

51CTO技術棧公眾號

www.成人.com| 国产一区二区不卡视频在线观看| 久久人人爽人人爽人人av| 国语对白在线视频| 婷婷六月综合| 亚洲性69xxxbbb| 成人18在线| 一区二区三区在线视频观看58| 自拍偷拍一区二区三区| 亚洲午夜久久| 九九精品在线播放| 欧美aa免费在线| 91精品国产综合久久久久久久 | 欧美中文字幕久久| 91国产精品视频在线观看| 激情国产一区二区| 一区二区三区我不卡| 一区二区三区四区五区在线| 国产精品久久久久久久久久久久久| 婷婷六月国产精品久久不卡| 精品欧美乱码久久久久久| 国产最新视频在线| 日韩欧美在线视频免费观看| 国产女主播在线| 高清不卡一区二区在线| 一区二区日本伦理| 经典一区二区三区| 精品国产一区三区| 中文字幕av一区二区三区高| 成人黄色片视频| 一区二区三区鲁丝不卡| 在线午夜视频| 91成人免费在线| 18加网站在线| 亚洲天堂日韩电影| 试看120秒一区二区三区| 人九九综合九九宗合| 一区二区电影在线观看| 国严精品久久久久久亚洲影视| 麻豆精品视频在线观看视频| 日韩欧美一区三区| 亚洲免费在线电影| 搞黄网站在线看| 午夜精品一区二区三区在线| 午夜精品电影| 97netav| 亚洲人成电影| 国产欧美一区二区精品仙草咪| 亚洲自拍偷拍图区| 天天射综合网站| 精品国产成人在线影院| 国产精品日本一区二区三区在线| 国产日韩欧美视频在线| 麻豆精品国产91久久久久久| www.99.热| 日韩国产高清视频在线| 日韩电影在线视频| 欧美日韩在线一| 色婷婷一区二区三区四区| 精品一区二区三区免费看| 欧美久久久久久一卡四| 亚洲女子a中天字幕| 亚洲女色av| 成人美女免费网站视频| 91在线观看下载| 伊人久久高清| 五码日韩精品一区二区三区视频| 亚洲国产日韩一级| 97久久亚洲| 免费av手机在线观看| 欧美不卡一区二区三区四区| 91偷拍一区二区三区精品| 孩娇小videos精品| 日韩亚洲欧美中文在线| 免费不卡在线观看| aaa在线免费观看| 中文在线资源观看网站视频免费不卡| 国产三级伦理在线| 亚洲一区二区三区精品动漫| 欧美性做爰猛烈叫床潮| 亚洲理论电影网| 免费毛片在线| 成人国产精品av| 狠狠色香婷婷久久亚洲精品| 亚洲人成免费网站| 天堂av在线资源| 久久涩涩网站| 亚洲综合图色| 成人福利影院| 亚洲最大的av网站| 欧美偷拍一区二区| 蜜臀av性久久久久蜜臀aⅴ流畅 | 成人影院在线播放| 五月天婷亚洲天综合网鲁鲁鲁| 欧美成人艳星乳罩| 国产99久久久国产精品潘金| 亚洲第一二三四区| 男人操女人免费软件| 538国产精品一区二区免费视频| 亚洲精品日产精品乱码不卡| 一区二区影视| 456成人影院在线观看| 国产真人做爰毛片视频直播| 57pao成人永久免费视频| 欧美午夜视频一区二区| 亚洲澳门在线| 欧美性猛交xxx高清大费中文| 久久久999视频| 国产精品爽爽ⅴa在线观看| 欧美一区二区三区免费大片 | 夜夜嗨av色综合久久久综合网| 欧美激情一二三区| 国产精品三上| 午夜精品福利影院| 成人av免费| 啦啦啦在线视频免费观看高清中文| 97视频热人人精品| 中文字幕欧美日韩va免费视频| 亚洲午夜精品在线| 99久久精品免费看国产| 久久福利一区| 精品日韩免费| 日韩不卡视频在线观看| 丝袜足控免费网站xx网站| eeuss中文| 日本亚洲精品在线观看| 美女网站久久| 欧美大香线蕉线伊人久久| 日韩一区二区三区免费看 | 中文字幕色一区二区| 成人黄色生活片| 午夜精品久久久久久久99热浪潮| 欧美日韩一区二区三区在线| 中文字幕一区在线观看| wwwwxxxxx欧美| 不卡视频在线观看| 日韩国产高清影视| 日韩精品亚洲专区| 日韩一级网站| 国产欧美日本| 日韩午夜黄色| 另类的小说在线视频另类成人小视频在线| 欧美1区2区| 欧美激情91| 性欧美videos另类喷潮| 免费视频一区| 精品无人码麻豆乱码1区2区 | 黄页网址大全在线观看| 色婷婷综合缴情免费观看| 宅男深夜国产| 992tv免费直播在线观看| 18videosex性欧美麻豆| 免费看a在线观看| 中文字幕在线直播| 亚洲欧洲二区| 日韩成人av在线资源| 中文无码久久精品| 久久免费黄色| 成人18视频在线播放| 国产精品色在线观看| 亚洲一区二区在线播放相泽| 五月婷婷综合网| 欧美一三区三区四区免费在线看| 亚洲国产精品成人一区二区| 最近2019中文免费高清视频观看www99 | 男人添女人下面高潮视频| 国产精品电影观看| 国产精品日韩一区二区| 欧美在线激情| 高清视频在线观看一区| 成人av在线网址| 亚洲精品日韩激情在线电影| 国产精自产拍久久久久久| 国产欧美日韩精品专区| 欧美成人亚洲成人日韩成人| 久久97精品久久久久久久不卡| 78色国产精品| 成人福利视频网| 国产成人一二三区| 亚欧美在线观看| 国产视频三级在线观看播放| 在线āv视频| 久久99国产精品视频| 欧美1级日本1级| 国产自产高清不卡| 欧美日韩在线看| 亚洲图片欧洲图片av| 91av在线网站| 亚洲专区在线视频| 婷婷国产在线| 亚洲国产精品传媒在线观看| av激情综合网| 亚洲欧美国产毛片在线| 日韩一区二区三区电影在线观看 | 欧美一级高清免费| 精品一区二区三区免费毛片| 北条麻妃在线视频观看| 三级毛片在线免费看| 风间由美中文字幕在线看视频国产欧美| 亚洲性视频在线|