Python装饰器新境界:详解装饰器重载内置操作

发布时间:2023年12月17日

ee755d6a56d383680cbedcba5beccd8c.jpeg

更多Python学习内容:ipengtao.com

大家好,我是彭涛,今天为大家分享 Python装饰器新境界:详解装饰器重载内置操作,全文3900字,阅读大约15分钟。

Python装饰器重载内置操作,我们通常指的是使用装饰器来修改或增强内置函数或方法的行为。这样的技术可以为我们提供一种灵活而强大的方式,以适应特定需求,同时保留原始函数或方法的结构。在本文中,我们将深入探讨Python装饰器的基础知识,并提供一些详细而全面的示例代码。

装饰器基础

装饰器是一种用于修改函数或方法行为的高阶函数。在Python中,装饰器通常以@decorator的形式使用,将其放在函数或方法定义之前。

def?my_decorator(func):
????def?wrapper(*args,?**kwargs):
????????print("Something?is?happening?before?the?function?is?called.")
????????result?=?func(*args,?**kwargs)
????????print("Something?is?happening?after?the?function?is?called.")
????????return?result
????return?wrapper

@my_decorator
def?say_hello():
????print("Hello!")

say_hello()

在上面的例子中,my_decorator是一个简单的装饰器,它在目标函数say_hello被调用前后打印一些信息。

装饰器重载内置操作

要重载内置操作,可以使用functools模块中的wraps装饰器,确保被装饰的函数保留原始函数的文档字符串和名称。接下来,将介绍如何重载内置的__call____getitem__方法。

1 重载__call__

from?functools?import?wraps

def?my_callable_decorator(func):
????@wraps(func)
????def?wrapper(*args,?**kwargs):
????????print(f"Calling?{func.__name__}?with?arguments:?{args},?{kwargs}")
????????result?=?func(*args,?**kwargs)
????????print(f"{func.__name__}?returned:?{result}")
????????return?result
????return?wrapper

@my_callable_decorator
def?add(a,?b):
????"""Adds?two?numbers."""
????return?a?+?b

add(3,?5)

在上面的例子中,创建了一个装饰器my_callable_decorator,它重载了add函数的__call__方法,以在函数调用前后输出相关信息。

2 重载__getitem__

from?functools?import?wraps

def?my_getitem_decorator(func):
????@wraps(func)
????def?wrapper(*args,?**kwargs):
????????key?=?args[0]
????????print(f"Getting?item?with?key:?{key}")
????????result?=?func(*args,?**kwargs)
????????print(f"Item?value:?{result}")
????????return?result
????return?wrapper

@my_getitem_decorator
def?get_item(data,?key):
????"""Gets?an?item?from?the?data?dictionary."""
????return?data[key]

my_data?=?{'name':?'John',?'age':?30}
get_item(my_data,?'name')

在这个示例中,定义了一个装饰器my_getitem_decorator,它重载了get_item函数的__getitem__方法,以在获取字典项前后输出相关信息。

装饰器链与参数传递

有时候,可能需要将多个装饰器链式组合,或者向装饰器传递参数。

下面的例子演示了如何实现这两个方面的需求。

from?functools?import?wraps

def?log_parameters(func):
????@wraps(func)
????def?wrapper(*args,?**kwargs):
????????print(f"Function?{func.__name__}?called?with?arguments:?{args},?{kwargs}")
????????return?func(*args,?**kwargs)
????return?wrapper

def?square_result(func):
????@wraps(func)
????def?wrapper(*args,?**kwargs):
????????result?=?func(*args,?**kwargs)
????????squared_result?=?result?**?2
????????print(f"Result?squared:?{squared_result}")
????????return?squared_result
????return?wrapper

@log_parameters
@square_result
def?add_and_multiply(a,?b,?c):
????"""Adds?three?numbers?and?multiplies?the?result."""
????return?(a?+?b)?*?c

result?=?add_and_multiply(2,?3,?4)

在上述例子中,创建了两个装饰器log_parameterssquare_result,然后将它们应用于add_and_multiply函数。log_parameters装饰器用于记录函数调用的参数,而square_result装饰器用于将函数结果平方并输出。

装饰器类与属性访问

有时候,可能需要使用类来实现装饰器,以便在装饰器中保持状态或提供更复杂的逻辑。

以下示例展示了如何使用类实现一个装饰器,该装饰器用于记录函数调用次数并提供属性访问。

from?functools?import?wraps

class?CountCalls:
????def?__init__(self,?func):
????????wraps(func)(self)
????????self._call_count?=?0

????def?__call__(self,?*args,?**kwargs):
????????self._call_count?+=?1
????????print(f"Function?{self.__name__}?called?{self._call_count}?times")
????????return?self.__wrapped__(*args,?**kwargs)

@CountCalls
def?greet(name):
????"""Greets?a?person?by?name."""
????return?f"Hello,?{name}!"

result?=?greet("Alice")
result?=?greet("Bob")

在上述示例中,创建了一个名为CountCalls的装饰器类,它实现了__init____call__方法。__init__方法用于初始化内部状态,而__call__方法用于实现函数调用时的逻辑。通过wraps(func)(self)语句,我们确保了被装饰函数保留了原始函数的名称和文档字符串。

装饰器与参数传递

如果需要向类装饰器传递参数,可以在类定义中增加一个额外的方法来接收这些参数。

以下示例演示了如何向类装饰器传递参数,并在装饰器中使用这些参数。

from?functools?import?wraps

class?LogMultiplier:
????def?__init__(self,?multiplier):
????????self.multiplier?=?multiplier

????def?__call__(self,?func):
????????@wraps(func)
????????def?wrapper(*args,?**kwargs):
????????????result?=?func(*args,?**kwargs)
????????????multiplied_result?=?result?*?self.multiplier
????????????print(f"Result?multiplied?by?{self.multiplier}:?{multiplied_result}")
????????????return?multiplied_result
????????return?wrapper

@LogMultiplier(multiplier=3)
def?add(a,?b):
????"""Adds?two?numbers."""
????return?a?+?b

result?=?add(2,?3)

在这个例子中,定义了一个名为LogMultiplier的类装饰器,该装饰器接收一个multiplier参数。在类的__call__方法中,创建了一个新的函数wrapper,该函数在调用原始函数后将结果乘以multiplier。通过使用@LogMultiplier(multiplier=3)语法,我们向装饰器传递了参数。

总结

在本文中,深入探讨了Python装饰器如何重载内置操作的方方面面,并提供了详尽的示例代码。首先回顾了装饰器的基础知识,强调了其作为高阶函数用于修改函数或方法行为的重要性。然后,关注了装饰器如何重载内置操作,详细介绍了重载__call____getitem__方法的示例。通过这些示例,读者能够清晰地了解如何在函数调用前后插入自定义逻辑,以适应特定需求。

进一步讨论了装饰器链与参数传递,演示了如何链式组合多个装饰器以及向装饰器传递参数的实现方式。这展示了装饰器的灵活性,能够根据具体情况构建复杂而强大的功能。此外,还介绍了使用类实现装饰器的方法,强调了类装饰器在保持状态和提供更复杂逻辑方面的优势。最后,演示了如何在类装饰器中实现参数传递,使得装饰器变得更加可配置。

总体而言,本文通过丰富的示例代码全面探讨了Python装饰器的应用,大家可以更深入地理解如何利用装饰器实现定制化的函数和方法行为,提高代码的可读性和可维护性。

如果你觉得文章还不错,请大家 点赞、分享、留言 下,因为这将是我持续输出更多优质文章的最强动力!

更多Python学习内容:ipengtao.com

干货笔记整理

? 100个爬虫常见问题.pdf ,太全了!

Python 自动化运维 100个常见问题.pdf

Python Web 开发常见的100个问题.pdf

124个Python案例,完整源代码!

PYTHON 3.10中文版官方文档

耗时三个月整理的《Python之路2.0.pdf》开放下载

最经典的编程教材《Think Python》开源中文版.PDF下载

2635fb0d0d48384f170e66ac68c2ceb2.png

点击“阅读原文”,获取更多学习内容

文章来源:https://blog.csdn.net/wuShiJingZuo/article/details/135027821
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。