Python中闭包、装饰器的概念

1.闭包(Closure)的概念:

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

 1 passline = 60
 2 def func(val):
 3     print('%x' % id(val))
 4     if val >= passline:
 5         print('pass')
 6     else:
 7         print('faild')
 8 
 9     def in_func():
10         print(val)
11 
12     in_func()
13     return in_func
14 
15 f = func(80)
16 f() #in_func
17 print(f.__closure__)

运行结果:

5d4ff910
pass
80
80
(<cell at 0x000001B37C8B6CD8: int object at 0x000000005D4FF910>,)


按照正常的理解,当执行完func函数后,in_func函数无法使用func函数作用域内的变量val,但是通过上面的代码,可以看到val添加到了in_func的__closure__属性中(in_func的属性__closure__对val变量进行了引用,func执行完成后val没有被释放掉),

也就是说,在函数闭包中,内部函数中对enclosing作用域的变量进行引用,并将引用变量添加到了内部函数__closure__属性中

2.装饰器

所谓装饰器,是用来装饰函数,并且返回一个函数对象

如以下求和与求平均值的两个方法:

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

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

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

其中,两个方法中都有相同的一段的容错处理代码: 

if len(arg) == 0:
        return 0
    for item in arg:
        if not isinstance(item, int):
            return 0

遵循程序设计的DRY原则,这段代码应该进行封装处理,这时便可引入函数闭包

def dec(func):
    def in_func(*args):
        if len(args) == 0:
            return 0
        for item in args:
            if not isinstance(item, int):
                return 0
        return func(*args)
    return in_func

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

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

my_sum=dec(my_sum)
my_average=dec(my_average)

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

这样就对重复的代码进行了封装。而装饰器是一种语法糖,简化了代码的编写

def dec(func):
    print('dec called')
    def in_func(*args):
        if len(args) == 0:
            return 0
        for item in args:
            if not isinstance(item, int):
                return 0
        return func(*args)
    return in_func

@dec
def my_sum(*args):
    print('my_sum called')
    return sum(args)
@dec
def my_average(*args):
    print('my_average called')
    return sum(args) / len(args)

# my_sum=dec(my_sum)
# my_average=dec(my_average)

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

运行结果:

dec called
dec called
my_sum called
6
0
程序执行到@dec时,调用 dec方法,返回in_dec,my_sum方法重新被赋值my_sum=in_dec(被装饰函数指向新的函数)
所以,装饰器@dec的作用就如同执行这行代码:
my_sum=dec(my_sum)
原文地址:https://www.cnblogs.com/liubiao/p/5278335.html