详解Python的装饰器 通俗易懂的解释!

Python装饰器是实现切面需求的绝佳设计,它允许在不修改原有代码的情况下为函数添加额外功能,如日志记录、性能测试、事务处理等。本文详细讲解了装饰器的基本概念、如何编写装饰器、高级装饰器如带参数的装饰器和类装饰器,以及内置的装饰器如`@staticmethod`和`@classmethod`。同时,还探讨了装饰器的潜在问题和如何优化装饰器的使用,包括使用`functools.wraps`和第三方库`decorator`、`wrapt`。
摘要由CSDN通过智能技术生成

详解Python的装饰器
Python中的装饰器是你进入Python大门的一道坎,不管你跨不跨过去它都在那里。

为什么需要装饰器
我们假设你的程序实现了say_hello()和say_goodbye()两个函数。

def say_hello():
print “hello!”

def say_goodbye():
print “hello!” # bug here

if name == ‘main’:
say_hello()
say_goodbye()
但是在实际调用中,我们发现程序出错了,上面的代码打印了两个hello。经过调试你发现是say_goodbye()出错了。老板要求调用每个方法前都要记录进入函数的名称,比如这样:

[DEBUG]: Enter say_hello()
Hello!
[DEBUG]: Enter say_goodbye()
Goodbye!
好,小A是个毕业生,他是这样实现的。

def say_hello():
print “[DEBUG]: enter say_hello()”
print “hello!”

def say_goodbye():
print “[DEBUG]: enter say_goodbye()”
print “hello!”

if name == ‘main’:
say_hello()
say_goodbye()
很low吧? 嗯是的。小B工作有一段时间了,他告诉小A可以这样写。

def debug():
import inspect
caller_name = inspect.stack()[1][3]
print “[DEBUG]: enter {}()”.format(caller_name)

def say_hello():
debug()
print “hello!”

def say_goodbye():
debug()
print “goodbye!”

if name == ‘main’:
say_hello()
say_goodbye()
是不是好一点?那当然,但是每个业务函数里都要调用一下debug()函数,是不是很难受?万一老板说say相关的函数不用debug,do相关的才需要呢?

那么装饰器这时候应该登场了。

装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。

概括的讲,装饰器的作用就是为已经存在的函数或对象添加额外的功能。

怎么写一个装饰器
在早些时候 (Python Version < 2.4,2004年以前),为一个函数添加额外功能的写法是这样的。

def debug(func):
def wrapper():
print “[DEBUG]: enter {}()”.format(func.name)
return func()
return wrapper

def say_hello():
print “hello!”

say_hello = debug(say_hello) # 添加功能并保持原函数名不变
上面的debug函数其实已经是一个装饰器了,它对原函数做了包装并返回了另外一个函数,额外添加了一些功能。因为这样写实在不太优雅,在后面版本的Python中支持了@语法糖,下面代码等同于早期的写法。

def debug(func):
def wrapper():
print “[DEBUG]: enter {}()”.format(func.name)
return func()
return wrapper

@debug
def say_hello():
print “hello!”
这是最简单的装饰器,但是有一个问题,如果被装饰的函数需要传入参数,那么这个装饰器就坏了。因为返回的函数并不能接受参数,你可以指定装饰器函数wrapper接受和原函数一样的参数,比如:

def debug(func):
def wrapper(something): # 指定一毛一样的参数
print “[DEBUG]: enter {}()”.format(func.name)
return func(something)
return wrapper # 返回包装过函数

@debug
def say(something):
print “hello {}!”.format(something)
这样你就解决了一个问题,但又多了N个问题。因为函数有千千万,你只管你自己的函数,别人的函数参数是什么样子,鬼知道?还好Python提供了可变参数*args和关键字参数**kwargs,有了这两个参数,装饰器就可以用于任意目标函数了。

def debu

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值