開始使用Python程式設計時,如果沒記錯的話,版本是3.3。因此,當我開始編程時,Python 社群很早就可以使用裝飾器了。
Python 2.2 版本引入了函數裝飾器,Python 2.6 版本引入了類別裝飾器。
就我個人而言,我認為 Python 的裝飾器功能是該語言的一個非常強大的功能。
實際上,我的目標是製作一系列有關 Python 中最難理解的主題的文章。我打算一一涵蓋這些主題,大概有十多個。
在本文中,我將嘗試盡可能多地觸及裝飾器主題的每個部分。
本質上,裝飾器是Python中的一種設計模式,它允許您修改函數或類別的行為而不改變其核心結構。裝飾器是元程式設計的一種形式,您本質上是在編寫操作其他程式碼的程式碼。
您知道 Python 使用以下順序給出的範圍來解析名稱:
裝飾器是坐封閉作用域,這與閉包概念密切相關。
關鍵思想:裝飾器將函數作為輸入,向其添加一些功能,然後返回修改後的函數。
類比:將裝飾器視為禮品包裝紙。您有一件禮物(原始功能),然後用裝飾紙(裝飾器)將其包裹起來,使其看起來更漂亮或添加額外的功能(例如蝴蝶結或卡片)。裡面的禮物保持不變,但它的呈現或相關動作得到了增強。
Python 中的大多數裝飾器都是使用函數實現的,但您也可以使用類別建立裝飾器。
基於函數的裝飾器更常見、更簡單,而基於類別的裝飾器提供了額外的靈活性。
def my_decorator(func): def wrapper(*args, **kwargs): # Do something before calling the decorated function print("Before function call") result = func(*args, **kwargs) # Do something after calling the decorated function print("After function call") return result return wrapper @my_decorator def say_hello(name): print(f"Hello, {name}!") say_hello("World")
說明:
它們使用類別而不是函數來定義裝飾器。
class MyDecorator: def __init__(self, func): self.func = func def __call__(self, *args, **kwargs): # Do something before calling the decorated function print("Before function call") result = self.func(*args, **kwargs) # Do something after calling the decorated function print("After function call") return result @MyDecorator def say_hello(name): print(f"Hello, {name}!") say_hello("World")
說明:
裝飾器的基本概念是它們是將另一個函數作為參數並擴展其行為而不明確修改它的函數。
這是最簡單的形式:
def my_decorator(func): def wrapper(): print("Something is happening before the function is called.") func() print("Something is happening after the function is called.") return wrapper # Using the decorator with @ syntax @my_decorator def say_hello(): print("Hello!") # When we call say_hello() say_hello() # This is equivalent to: # say_hello = my_decorator(say_hello)
讓我們建立一個記錄函數執行時間的裝飾器:
def decorator_with_args(func): def wrapper(*args, **kwargs): # Accept any number of arguments print(f"Arguments received: {args}, {kwargs}") return func(*args, **kwargs) # Pass arguments to the original function return wrapper @decorator_with_args def greet(name, greeting="Hello"): print(f"{greeting}, {name}!") greet("Alice", greeting="Hi") # Prints arguments then "Hi, Alice!"
這些裝飾器可以接受自己的參數:
def repeat(times): def decorator(func): def wrapper(*args, **kwargs): for _ in range(times): result = func(*args, **kwargs) return result return wrapper return decorator @repeat(times=3) def greet(name): print(f"Hello {name}") return "Done" greet("Bob") # Prints "Hello Bob" three times
def singleton(cls): instances = {} def get_instance(*args, **kwargs): if cls not in instances: instances[cls] = cls(*args, **kwargs) return instances[cls] return get_instance @singleton class DatabaseConnection: def __init__(self): print("Initializing database connection") # Creating multiple instances actually returns the same instance db1 = DatabaseConnection() # Prints initialization db2 = DatabaseConnection() # No initialization printed print(db1 is db2) # True
這些是專門為類別方法設計的:
def debug_method(func): def wrapper(self, *args, **kwargs): print(f"Calling method {func.__name__} of {self.__class__.__name__}") return func(self, *args, **kwargs) return wrapper class MyClass: @debug_method def my_method(self, x, y): return x + y obj = MyClass() print(obj.my_method(5, 3))
多個裝飾器可以應用於單一函數:
def bold(func): def wrapper(): return "<b>" + func() + "</b>" return wrapper def italic(func): def wrapper(): return "<i>" + func() + "</i>" return wrapper @bold @italic def greet(): return "Hello!" print(greet()) # Outputs: <b><i>Hello!</i></b>
說明:
functools.wraps 裝飾器(請參閱文件)是一個輔助函數,當您使用裝飾器包裝原始函數時,它會保留原始函數的元資料(如其名稱、文件字串和簽名)。如果您不使用它,您將丟失這些重要資訊。
範例:
def my_decorator(func): def wrapper(*args, **kwargs): """Wrapper docstring""" return func(*args, **kwargs) return wrapper @my_decorator def my_function(): """My function docstring""" pass print(my_function.__name__) print(my_function.__doc__)
輸出:
wrapper Wrapper docstring
問題:
解:使用 functools.wraps):
def my_decorator(func): def wrapper(*args, **kwargs): # Do something before calling the decorated function print("Before function call") result = func(*args, **kwargs) # Do something after calling the decorated function print("After function call") return result return wrapper @my_decorator def say_hello(name): print(f"Hello, {name}!") say_hello("World")
輸出:
class MyDecorator: def __init__(self, func): self.func = func def __call__(self, *args, **kwargs): # Do something before calling the decorated function print("Before function call") result = self.func(*args, **kwargs) # Do something after calling the decorated function print("After function call") return result @MyDecorator def say_hello(name): print(f"Hello, {name}!") say_hello("World")
裝飾器也可以維護函數呼叫之間的狀態。這對於緩存或計算函數呼叫等場景特別有用。
def my_decorator(func): def wrapper(): print("Something is happening before the function is called.") func() print("Something is happening after the function is called.") return wrapper # Using the decorator with @ syntax @my_decorator def say_hello(): print("Hello!") # When we call say_hello() say_hello() # This is equivalent to: # say_hello = my_decorator(say_hello)
輸出:
def decorator_with_args(func): def wrapper(*args, **kwargs): # Accept any number of arguments print(f"Arguments received: {args}, {kwargs}") return func(*args, **kwargs) # Pass arguments to the original function return wrapper @decorator_with_args def greet(name, greeting="Hello"): print(f"{greeting}, {name}!") greet("Alice", greeting="Hi") # Prints arguments then "Hi, Alice!"
說明:
包裝函數維護一個計數器(呼叫),每次呼叫裝飾函數時該計數器都會增加。
這是一個如何使用裝飾器來維護狀態的簡單範例。
您可以在下面找到 Python 裝飾器的精選清單:
裝飾器是 Python 中一個強大而優雅的功能,它允許您以乾淨和聲明性的方式增強函數和類別。
透過了解原理、最佳實踐和潛在陷阱,您可以有效地利用裝飾器來編寫更模組化、可維護和富有表現力的程式碼。
它們是任何 Python 程式設計師的武器庫中的寶貴工具,特別是在使用框架或建立可重複使用元件時。
以上是Python 裝飾器:綜合指南的詳細內容。更多資訊請關注PHP中文網其他相關文章!