python装饰器扩展(作用域,闭包)

1.函数作用域

函数作用域LEGB,L>E>G>B
- L : local 函数内部作用域
- E : enclosing 函数内部与内嵌函数之间
- G :global 全局作用域
- B : build-in 内置作用域
变量和函数查找

passline = 60

def checkvalue(val):
    passline = 90
    if val > passline:
        print('pass')
    else:
        print('failed')
    def func()
        val = str(val)
        print(val)
    func(val)

checkvalue(93)

python运行时fun()函数时,def内部即是local,
checkvalue()内部即是enclosing
第一行函数体外定义的passline即是global
str函数即是bulid-in 内置作用域

2.python闭包

closure:内部函数中对enclosing作用域的变量进行引用

函数实质与属性

  1. 函数是一个对象
  2. 函数执行后完成内部变量回收
  3. 函数属性
  4. 函数返回值

继续引用上述代码

def check(val):
    passline = 100
    #以16进制打印val的id值
    print('%x'%id(val))
    if val > 60:
        print('pass')
    else:
        print('fail')
    def func():
        print(val)
    func()
    return func

f = check(90)

当调用f = check(90)时,输出结果为

1009dd4a0
pass
90

此时可看出val的id值为1009dd4a0
然后再执行:f()

90

按照python的变量回收机制,val在check函数执行完成后,应该被回收掉,为什么会出现调用f()时,出现val的值呢
此时再执行:

print(f.__closure__)

输出值为

(<cell at 0x105fed6d8: int object at 0x1009dd4a0>,)

由此可看出,f中存在int类型的val值的引用,因为python采用引用计数的垃圾回收机制,当check()函数执行完成后,val对象被保存在func的函数属性中,仍存在引用,所以并没有对val进行垃圾回收。

闭包

闭包实质上是一个函数,它使得函数在执行后,函数的返回对象不会被内存回收,闭包中包含着自由变量,只要闭包能被访问到,自由变量就可以被访问。
在上述代码中f = check()就是一个闭包
每个函数都有一个_closuer_属性,如果这个函数是一个闭包的话,那么这个函数的返回值就是一个由cell对象组成的元组,cell对象中的cell_contents属性值就是闭包中的自由变量
测试代码:

c = f.__colsure__[0].cell_contents

#90

可以看到c的值为90
val的值被储存在闭包对象的cell_contents中,所以在闭包函数外部可以访问函数内部变量
闭包的好处:
1. 代码的复用
2. 封装

3.装饰器

  1. 装饰器用来装饰函数
  2. 返回一个函数对象
  3. 被装饰函数标识符指向返回的函数对象
  4. 语法糖 @

装饰器是对闭包的一种实现方式

假设有两个班,1班人数为40人,二班人数为30人,每天需要对两个班的考勤做出统计,
考勤规则为:出勤的人数大于班级人数的80%,考勤则通过,否则不通过。
题目:设计考勤函数
  • 使用两个函数分别考勤
#1班考勤办法
def check_1(num):
    ##班级人数
    total = 40
    if num > total * 0.8:
        print('ok')
    else:
        print('fail')

#2班考勤办法
def check_2(num):
    total = 30
    if num > total * 0.8:
        print('ok')
    else:
        print('fail')
突然有一天,增加需求,需要对每个班的人数进行判断,如果这个班到的人数少于10人,考核为不及格。这时候如果班级数量很多,就需要重复去写相同的代码,此时就需要装饰器
#将原本每个班的判断函数传入
def dec(func):
    def _wrapper(num):
        if num < 10:
            print('不及格')
        return func(num)
    return _wrapper

#为原本函数加上装饰器
@dec
def check_2(num):
    total = 30
    if num > total * 0.8:
        print('ok')
    else:
        print('fail')


print(check_2(2))

#---> 不及格
#---> fail

猜你喜欢

转载自blog.csdn.net/weixin_35993084/article/details/80786211