天天看點

中高階Python正常用法--上下文管理器

作者:攻城獅奶爸雜貨鋪

Python 以簡單性和通用性著稱,是一種深受全球開發人員喜愛的程式設計語言。它提供了大量的特性和功能,使編碼成為一種愉快的體驗。在這些功能中,一個經常被新手忽視的強大工具是上下文管理器。上下文管理器是進階構造,可實作簡潔高效的資源管理,同時確定正确處理異常和清理操作。在此部落格中,我們将深入了解上下文管理器的世界,了解它們是什麼、它們如何工作以及它們如何将您的 Python 代碼提升到新的高度。

了解上下文管理器:

在 Python 中,上下文管理器是一個對象,它定義了方法 __enter__() 和 __exit__() 以在特定上下文中啟用資源管理。它允許您自動配置設定和釋放資源、執行設定和拆卸操作以及優雅地處理異常。

`__enter__()` 方法在上下文的開頭執行,您可以在其中設定任何資源或執行必要的初始化。當在“with”語句中使用上下文管理器時,該方法傳回将與“as”關鍵字關聯的對象或值。

`__exit__()` 方法在上下文結束時被調用,無論是執行成功還是出現異常。它負責清理資源、關閉檔案或連接配接,或任何其他必要的拆卸操作。它還接收有關在上下文中引發的任何異常的資訊,進而提供異常處理的機會。

使用帶有 `with` 語句的上下文管理器:

使用上下文管理器的最常見和推薦的方法是使用“with”語句。`with` 語句確定上下文管理器的 `__enter__()` 方法在塊的開頭被調用,而 `__exit__()` 方法在塊的末尾被調用,而不管中間可能發生的任何異常。

考慮以下示例:

with open('file.txt', 'r') as file:


  content = file.read()
  
  print(content)           

在上面的代碼中,`open()` 函數傳回一個處理檔案資源的上下文管理器。`with` 語句自動調用 `__enter__()` 方法,打開檔案,并将檔案對象配置設定給變量 `file`。執行塊後,将調用 __exit__() 方法,即使發生異常也會關閉檔案。

建立自定義上下文管理器:

雖然 Python 為許多場景提供了内置上下文管理器,但您也可以通過在類中實作 `__enter__()` 和 `__exit__()` 方法或使用 `contextlib` 子產品來建立自己的自定義上下文管理器。

建立自定義上下文管理器允許您封裝特定行為并提供可重用和幹淨的代碼。 例如,您可以建立一個資料庫連接配接上下文管理器,自動處理連接配接的建立和關閉,確定适當的資源管理。

上下文管理器的好處:

上下文管理器提供了幾個優勢,包括:

1. 資源管理:上下文管理器處理資源的擷取和釋放,例如檔案句柄、資料庫連接配接或網絡連接配接,無需手動清理。

2.異常處理:上下文管理器促進優雅的異常處理。`__exit__()` 方法允許您捕獲和處理上下文中引發的異常,進而啟用清理操作并防止資源洩漏。

3. 可讀性和簡潔性:`with` 語句通過消除與資源管理和錯誤處理相關的樣闆代碼,使代碼更具可讀性和簡潔性。

上面是一些理論的概述,下面我們從實際出發,給大家舉幾個例子。展示 Python 中上下文管理器的進階特性和功能:

1. 使用上下文管理器處理檔案:

class File:


  def __init__(self, filename, mode):
  
    self.filename = filename
    
    self.mode = mode
    
    self.file = None
  
  def __enter__(self):
  
    self.file = open(self.filename, self.mode)
    
    return self.file
  
  def __exit__(self, exc_type, exc_val, exc_tb):
  
    self.file.close()
  
# Usage:


with File('example.txt', 'w') as file:


  file.write('Hello, context managers!')           

在此示例中,我們建立了一個自定義上下文管理器“File”,它使用“with”語句自動打開和關閉檔案。檔案以寫入模式打開,内容寫入其中。一旦執行了 `with` 塊,就會調用 `__exit__()` 方法,關閉檔案。

2. 與上下文管理器的資料庫連接配接(使用 `contextlib`):

from contextlib import contextmanager


import sqlite3


@contextmanager


def database_connection(database):


    connection = sqlite3.connect(database)


    cursor = connection.cursor()


    try:


        yield cursor


    finally:


        cursor.close()


        connection.close()


# Usage:


with database_connection('mydb.db') as cursor:


    cursor.execute('SELECT * FROM users')


    result = cursor.fetchall()


    for row in result:


        print(row)           

在此示例中,我們使用 contextlib 子產品中的 contextmanager 裝飾器為 SQLite 資料庫連接配接建立上下文管理器。`yield` 語句允許我們在上下文中與遊标進行互動。當“with”塊結束時,連接配接和遊标會自動關閉,確定正确的資源管理。

3.定時器上下文管理器:

import time


    class Timer:


    def __enter__(self):


        self.start_time = time.time()


    def __exit__(self, exc_type, exc_val, exc_tb):


        end_time = time.time()


        execution_time = end_time - self.start_time


        print(f"Execution time: {execution_time} seconds")


# Usage:


with Timer():


    # Perform some time-consuming operations


    time.sleep(3)           

在此示例中,我們建立了一個簡單的計時器上下文管理器,用于測量特定代碼塊的執行時間。 `__enter__()` 方法記錄開始時間,`__exit__()` 方法計算經過的時間并顯示。這對于分析代碼和優化性能很有用。

這些示例展示了 Python 中上下文管理器的多功能性和強大功能。無論您是處理檔案操作、資料庫連接配接還是性能監控,上下文管理器都提供了一種優雅而高效的方式來管理資源和處理異常。

是以了解和使用上下文管理器是每個 Python 開發人員都應該具備的寶貴技能。無論您是在處理檔案、資料庫還是任何其他需要仔細管理的資源,上下文管理器都提供了一個優雅的解決方案。通過自動處理資源配置設定、清理操作和異常處理,它們簡化了代碼,增強可讀性,并降低資源洩漏的風險。 是以,擁抱上下文管理器的強大功能并解鎖進階 Python 功能,将您的編碼工作提升到一個新的水準!

上期問題:我們如何在 Python 中将參數傳遞給裝飾器?

答:在 Python 中,裝飾器可以通過引入額外的嵌套層來接受參數。要将參數傳遞給裝飾器,您需要建立一個裝飾器工廠函數,它接受所需的參數并傳回裝飾器本身。下面是一個例子來說明這個概念:

def decorator_factory(argument):


  def decorator(func):
  
    def wrapper(*args, **kwargs):
    
      # Perform additional tasks using the 'argument'
      
      print(f"Decorator argument: {argument}")
    
      return func(*args, **kwargs)
  
  return wrapper
  
return decorator


@decorator_factory("Hello, World!")


def greet():


  print("Greetings!")


greet()           

在這個例子中,我們定義了一個接受參數的`decorator_factory`。它傳回實際的裝飾器函數,它接受目标函數并建立一個包裝器。包裝函數可以從外部作用域通路“參數”并基于它執行其他任務。當我們将裝飾器 @decorator_factory("Hello, World!") 應用于 greet 函數時,它添加了在執行 greet 函數之前列印裝飾器參數的額外功能。

此代碼的輸出将是:

Decorator argument: Hello, World!


Greetings!           

利用裝飾器工廠,我們可以根據傳遞給裝飾器的參數動态定制裝飾器的行為,使裝飾器更加靈活,适應各種場景。你學會了嗎?點個關注,後面還有更精彩的内容哦!