python装饰器

 1.装饰器是什么

      装饰器只是语法糖,是可调用的对象,可以像常规的可调用对象那样调用,特殊的地方是装饰器的参数是一个函数

      装饰器的存在是为了适用两个场景,一个是增强装饰函数的行为,另一个是代码重用

2 装饰器理解基础

   首先要了解下面两个知识

   (1)函数名可以赋值给变量

def func(name):
     print("我是{},慌得一比".format(name))
func("梅西")
y=func
y("内马尔")

 输出为:

我是梅西,慌得一比
我是内马尔,慌得一比

在代码中我们首先定义了函数 func,并调用了 func 函数,并且把 func 赋值给 y。y = func 表明了:函数名可以赋值给变量,并且不影响调用。

(2)高阶函数 

高阶函数满足如下的两个条件中的任意一个:a.可以接收函数名作为实参;b.返回值中可以包含函数名。

在 Python 标准库中的 map 和 filter 等函数就是高阶函数。

l = [1, 2, 4]
r = map(lambda x: x*3, l)
for i in r:
    print('当前天台人数:', i)

    输出结果:

当前天台人数: 3
当前天台人数: 6
当前天台人数: 12

   自定义一个返回函数的函数,也是高阶函数

def f(l):
    return map(lambda x: x *5, l)
a = f(l)
for i in a:
    print('当前天台人数:', i)
当前天台人数: 5
当前天台人数: 10
当前天台人数: 20

 

实现一个类似的装饰器

现在你已经知道了「函数名赋值」和「高阶函数」,有了这两个基础,我们就可以尝试实现一个类似的装饰器。

def status(func):
    print("慌得一匹")
    return func
def name():
    print("我是梅西")
temp=status(name)
temp()
慌的一逼!
我是梅西!

在这个例子中我们定义了一个 status 函数,status 接收一个函数名然后直接返回该函数名。这样我们实现了不修改原函数 name,并且添加了一个新功能的需求。但是这里有个缺陷就是函数的调用方式改变了。即不是原本的 name,而是 temp。 

要解决这个问题很简单,相信 a = a*3 这样的表达式大家都见过,那么上述代码中的 temp = status(name) 同样可以修改为 name = status(name),这样我们就完美的解决了问题:既添加新功能又没有修改原函数和其调用方式。修改后的代码如下:

def status(func):
    print('慌的一逼!')
    return func
def name():
    print('我是梅西!')
name = status(name)
name()

但这样的代码却有个不便之处,即每次使用这样的装饰器,我们都要写类似 name = status(name) 的代码。程序员都是懒的,所以才有那么多高级的语法。在 python 中为了简化这种情况,提供了一个语法糖 @,在每个被装饰的函数上方使用这个语法糖就可以省掉这一句代码 name = status(name),最后的代码如下:

def status(func):
    print("慌得一匹")
    return func
@status
def name():
    print("我是梅西")
name()

 

 这样我们就弄清楚了装饰器的原理:

1 写一个高级函数,即参数是函数,返回值也是韩束

2 在利用语法糖@,简化赋值操作

 那如果添加一个嵌套函数会是什么样的呢

def guess_win(func):
    def rooftop_status():
        result = func()
        print('天台已满,请排队!')
        return result
    return rooftop_status
@guess_win
def german_team():
    print('德国必胜!')

@guess_win等价于在代码最后一行输入:german_team=guess_win(german_team)

result=german_team() ,所以会先打印德国必胜 

德国必胜!
天台已满,请排队!

在这个例子中,我们还实现了一个 rooftop_status 函数,来判断下当前的天台状是否人满。但是我们现在是直接返回了函数名,这样函数调用后我们就没办法做任何事情,我们需要考虑下天台的情况。

为了能判断天台的情况,所以此时我们需要在嵌套一层函数,将实现额外功能的部分写在内层函数中,然后将这个内层函数返回即可。这也是为什么装饰器都是嵌套函数的原因。

 另外,这个例子并没有返回值,也没有参数,要对既有参数又有返回值的函数进行装饰的话,还需要进一步完善。 能够处理返回值的装饰器:

def guess_win(func):
    def rooftop_status():
        result = func()
        print('天台已满,请排队!')
        return result
    return rooftop_status
def german_team():
    print('德国必胜!')
    return '赢了会所嫩模!输了下海干活!'
german_team=guess_win(german_team)
x = german_team() #此处的X

#两个函数输出结果一样
def guess_win(func):
    def rooftop_status():
        result = func()
        print('天台已满,请排队!')
        return result
    return rooftop_status
@guess_win
def german_team():
    print('德国必胜!')
    return '赢了会所嫩模!输了下海干活!'
x = german_team()
德国必胜!
天台已满,请排队!
赢了会所嫩模!输了下海干活!

 能够处理参数的装饰器

 

def guess_win(func):
    def rooftop_status(*args, **kwargs):
        result = func(*args, **kwargs)
        print('天台已满,请排队!')
        return result
    return rooftop_status
@guess_win
def german_team(arg):
    print('{}必胜!'.format(arg))
    return '赢了会所嫩模!输了下海干活!'
x = german_team('德国')
y = german_team('西班牙')
print(x)
德国必胜!
天台已满,请排队!
西班牙必胜!
天台已满,请排队!
赢了会所嫩模!输了下海干活!

 

总结

装饰器的本质是函数,其参数是另一个函数(被装饰的函数)。装饰器通常会额外处理被装饰的函数,然后把它返回,或者将其替换成另一个函数或可调用对象。行为良好的装饰器可以重用,以减少代码量。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值