当我开始使用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中文网其他相关文章!