python装饰器_Python基础-装饰器

037b5f5e4f13eb71466c7128a493d31b.png
作者:Zarten 知乎专栏:Python基础深入详解 知乎ID: Zarten 简介: 互联网一线工作者,尊重原创并欢迎评论留言指出不足之处,也希望多些关注和点赞是给作者最好的鼓励 !

概述

装饰器其实就是一个函数,返回值是一个函数对象,它可以让其他函数在不需要做任何代码改动的前提下增加额外功能,比如:日志功能、性能测试、缓存、事务处理、权限校验等。

为了理解装饰器,我们要先理解一个概念,即:python里面一切皆对象,包括函数。

函数装饰器详解

最简单的装饰器

def my_decorator(f):
    return f

这个装饰器什么也没做,返回原函数对象。

装饰器的使用

def my_decorator(f):
    return f

@my_decorator
def fun():
    print('zarten')

fun()

上面代码等价于:

def my_decorator(f):
    return f

def fun():
    print('zarten')

fun = my_decorator(fun)
fun()

一般使用第一种方式,python中特有的装饰器语法,更加简洁。

装饰器返回另外一个函数

装饰器通常都是返回另外一个函数,而不是原函数本身

def my_decorator(f):
    def other_fun():
        print('other_fun')
    return other_fun

@my_decorator
def fun():
    print('zarten')

fun()
print(fun)

ffcab13e9ef2b6c1780e55311d76c990.png

调用fun()函数,其实是运行装饰器里面的other_fun()函数。从输出结果也可看到,fun()函数现在是other_fun()函数的引用。

从输出结果可以看到,并没有执行fun()函数内的代码,这是因为在装饰器内部执行了other_fun()函数,但并没有在内部执行fun()函数,所以一般在装饰器传入参数,这个参数是被装饰的函数对象,都会在装饰器内部调用并返回其结果

def my_decorator(f):
    def other_fun():
        print('other_fun')
        return f()
    return other_fun

@my_decorator
def fun():
    print('zarten')

fun()
print(fun)

0ed7159701698e0c0fc1cc5daf2494e2.png

functools.wraps的作用

我们知道,执行fun()函数,实际上是执行了装饰器里面的other_fun()函数,并在内部返回了原函数。但这样有个缺点是:原函数的一些元信息发生了改变,如docstring、__name__、参数列表等。如下代码所示:

def my_decorator(f):
    def other_fun():
        print('other_fun')
        return f()
    return other_fun

@my_decorator
def fun():
    print('zarten')

print('fun name:', fun.__name__)

b5dabcef5db9daa886f674a3ae516b8e.png

为了防止元信息改变,python引入了functools.wraps,用法如下

from functools import wraps
def my_decorator(f):
    @wraps(f)
    def other_fun():
        print('other_fun')
        return f()
    return other_fun

@my_decorator
def fun():
    print('zarten')

print('fun name:', fun.__name__)

7c83fe5b0877b0f19c0e6e5781f4aef0.png

一个完整简单的日志打印装饰器

from functools import wraps

def my_decorator(f):
    @wraps(f)
    def other_fun(*args, **kwargs):
        print('%s in running' % f.__name__)
        return f(*args, **kwargs)
    return other_fun

@my_decorator
def fun():
    print('zarten')
    
fun()

de5cfcfa4d161c7d382a1e7ebf0c6d3d.png

带参数的装饰器

装饰器是把被装饰函数作为第一个参数传进去,若装饰器带有参数时,怎么接收其他额外的参数呢?

方法是:将额外的参数作为第一个参数传进去,然后返回一个函数对象,这个函数的参数才是被装饰函数的对象

from functools import wraps

def my_decorator(zhihu_id= 'zarten'):
    def decorator(f):
        @wraps(f)
        def other_fun(*args, **kwargs):
            print('%s in running.name is %s' % (f.__name__, zhihu_id))
            return f(*args, **kwargs)

        return other_fun
    return decorator

@my_decorator('zarten_2')
def fun():
    print('zarten')

fun()

eb1bb8f540df85a82b10778f710829eb.png

从上面代码可以看到,装饰器使用的默认参数,若装饰器不传递任何参数时,也需要使用空括号,如@my_decorator()

类装饰器详解

类装饰器,也就是说装饰器是一个类了,而不是一个函数了。类装饰器和函数装饰器非常类似。

可以利用类的特殊方法__call__()来实现,实现此特殊方法后,类对象可以像函数一样调用。PS:若对python中的常用特殊方法不了解的,可以查看我之前写的文章,点这里。

类装饰器的实现

class Decorator():
    def __init__(self, f):
        self.f = f
        
    def __call__(self, *args, **kwargs):
        print('%s in running' % self.f.__name__)
        self.f(*args, **kwargs)

使用类装饰器

使用类装饰器跟使用函数装饰也是非常的类似

@Decorator
def fun():
    print('zarten')

fun()

bf51dc75a136187d0be5652f9d32ad10.png

此时被装饰的函数对象作为装饰器类的参数传入,返回一个类装饰器的对象,由于装饰器类里实现了__call__()的特殊方法,固可以直接调用这个对象。

若不使用@Decorator语法糖,上面代码等价于:

def fun():
    print('zarten')

fun = Decorator(fun)
fun()

完整代码如下:

class Decorator():
    def __init__(self, f):
        self.f = f

    def __call__(self, *args, **kwargs):
        print('%s in running' % self.f.__name__)
        self.f(*args, **kwargs)

@Decorator
def fun():
    print('zarten')

fun()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值