python装饰器

python闭包理解与使用

闭包:内部函数中对enclosing作用域的变量进行引用,看下面代码:

passline = 60

def checkFun(val):
    print("%x" %id(val))
    if val > passline:
        print('pass')
    else:
        print('fail')
    def in_fun():
        print(val)

    return in_fun

f = checkFun(77)
f() #  in_fun方法  
print(f.__closure__)

上面的代码中,当checkFun方法执行完成之后val的值是被释放的,那么我们调用checkFun的返回值,in_fun方法,会打印出来,其实python解释器将这个值放到方法的属性__closure__
这里写图片描述

那么这个和闭包有什么关系,试想如果某一门课程总分是150,那么我们可能需要设置90分为及格,改变上面的函数

def setPass(passline):  # 调用setPass(60)时候passline = 60
    def checkFun(val):
        if val > passline: # 将passline 添加到checkFun的__closur__中
            print('pass')
        else:
            print('fail')
    return checkFun

f_100 = setPass(60)
f_100(45)  #fail

f_150 = setPass(90)
f_150(109) #pass

上面的代码中,当调用setPass(60)时候,passline就等于60,那么这里返回的checkFun函数中,用到了passline,就会将passline添加到checkFun函数的__closure__属性中,,所以这里即使setPass方法执行结束,内部的passline也已经释放,但是由于解释器将passline添加到了__closure__属性中,所以我们依然可以获取其值,,这里返回的函数就成为闭包

使用闭包封装函数

在开始之前,我们先看下面栗子:

def my_sum(*arg):
    return sum(arg)

def my_average(*arg):
    return sum(arg) / len(arg)

print(my_sum(1,2,3))  # 6
print(my_average(1,2,3)) # 2

可以看到,上面的函数正常情况下可以正常输出,,那么如果我们传递一些非法参数呢?

def my_sum(*arg):
    return sum(arg)

def my_average(*arg):
    return sum(arg) / len(arg)

print(my_sum(1,2,3,'33'))
print(my_average())

此时程序运行,解释器会抛出下面异常:
这里写图片描述

修改上面的代码,添加如下判断:

def my_sum(*arg):
    if len(arg) == 0:
        return 0
    for v in arg:
        if not isinstance(v,int):
            return 0
    return sum(arg)

def my_average(*arg):
    if len(arg) == 0:
        return 0
    for v in arg:
        if not isinstance(v,int):
            return 0
    return sum(arg) / len(arg)

print(my_sum(1,2,3,'33'))  # 0
print(my_sum(1,2,3))    # 6
print(my_average(1,2,3))  # 2
print(my_average())  # 0

可以看到上面的代码可以正常输出了,不会抛出异常,但是上面的两个方法,都使用到了同样的代码块,这就有很大的冗余性,这里我们使用闭包来封装上面相同的代码块。如下:

def my_sum(*arg):
    return sum(arg)

def my_average(*arg):
    return sum(arg) / len(arg)

def sameCode(fun):
    def inFun(*arg):
        if len(arg) == 0:
            return 0
        for v in arg:
            if not isinstance(v,int):
                return 0
        return fun(*arg)
    return inFun

my_sum = sameCode(my_sum)     
print(my_sum(1,2,3))

my_average = sameCode(my_average)
print(my_average())

python装饰器

python装饰器:

  • 装饰器用来装饰函数
  • 返回一个函数对象
  • 被装饰函数标识符指向返回的函数对象
  • 语法:@dec
    这里我们可以将上面的代码使用装饰器进行改造
def sameCode(fun):
    print('inFun runs...')  #当使用@sameCode装饰器时候,会执行其内部封装的inFun方法
    def inFun(*arg):
        print('inFun runs ++++')
        if len(arg) == 0:
            return 0
        for v in arg:
            if not isinstance(v,int):
                return 0
        return fun(*arg)
    return inFun

@sameCode  #这里需要注意的是,装饰器必须写为被装饰的函数名称
def my_sum(*arg):
    print('my_sum runs...')
    return sum(arg)

print(my_sum(1,2,3,4))

此时打印如下:
这里写图片描述
这里需要注意的是,装饰器必须写为被装饰的函数名称
使用上面的装饰器装饰完成之后,实际上my_sum函数此时就指向inFun函数

@python装饰器理解

我们再来看下面的栗子

def dec(func):
    print('dec first...')
    def in_dec():
        print('in_dec runs...')
        func()
    print("dec end...")
    return in_dec

@dec  #使用@dec来装饰bar函数,此时会执行dec方法
def bar():
    print('bar runs....')
bar()  #装饰完成,bar函数指向返回的in_dec函数

此时运行结果如下:
这里写图片描述

那么如果我们的bar函数需要传递参数,我们可以这样做:

def dec(func):
    print('dec first...')
    def in_dec(num1, num2):
        print('in_dec runs...')
        func(num1,num2)
    print("dec end...")
    return in_dec

@dec
def bar(num1, num2):
    print('bar runs....sum is :',num1+num2)
bar(2,3)

当我们使用@dec装饰器装饰玩bar函数之后,bar其实就指向了dec返回的in_dec函数,所以这里需要in_dec来接收参数,此时效果如下:
这里写图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值