Python闭包、装饰器

慕课网课程笔记,网上文章总结

1.Python装饰器之函数作用域LEGB

LEGB(L>E>G>B):

  • L:local 函数内部作用域(局部名字空间)
  • E:enclosing 函数内部与内嵌函数之间(直接外围空间)
  • G:global 全局作用域
  • B:build-in 内置作用域
-- enclosing 作用域示例
def func(val):
    -- 局部/内部作用域
    passline = 90
    def in_func():
        -- val就是enclosing作用域
        print(val)
    in_func()

func(89)

总结:就近原则

2.Python装饰器之闭包

闭包:内部函数对enclosing作用域地变量进行引用。

简单点说,就是内部的函数调用外界的变量,外界的变量变了,内部的变量也就变了。我们要注意的就是返回和传入的对象,是函数,注意掌握变量的作用范围。(同时,为了在外部调用内部的函数,做法就是将内部函数返回。)

函数实质与属性:

  • 函数是一个对象
  • 函数执行完后内部变量回收
  • 函数属性
  • 函数返回值
--
passline= 68

def func(val):
    -- 打印出val 空间值
    print("%x"%id(val))
    if val >= passline:
        print('pass')
    else:
        print('failed')
    def in_func(): # val会添加为函数in_func的属性
        -- val就是enclosing作用域
        print(val)
    in_func()
    -- 返回内部函数
    return in_func

-- 将返回的内部函数变量赋给f 
f = func(89)
-- 调用内部函数
f()
print(f.__closure__)

-- 打印结果
((int object at oxoooooo5FCCC1B0),)
89
89
((int object at oxoooooo5FCCC1B0),)

附注:从结果可以看出,引用的外部变量(val)会添加到函数的属性中。

def set_passline(passline):
    def cmp(val): #外部变量passline会添加到函数cmp的属性中
        if val>=passline:
            print('pass')
        else:
            print('failed')
    return cmp

func_100=set_passline(60)
func_150=set_passline(90)
func_100(89)
func_150(89)
-- 返回的是cmp函数,func_100=cmp,然后传值再比较

闭包作用:

  • 封装
  • 代码复用
-- 上面参数是数值/变量,如果是函数怎么样?

-- *arg表示可变长参数
def my_sum(*arg):
    return sum(arg)
def my_average(*arg):
    return sum(arg)/len(arg)

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

-- 闭包
def my_sum(*arg):
    return sum(arg)
def my_average(*arg):
    return sum(arg)/len(arg)

def dec(func):
    def in_dec(*arg): #my_sum、my_average作为func参数传入时,会成为in_dec函数的属性

        if len(arg) == 0;
            return 0
        for val in arg:
            if not ininstance(val,int)
            return 0
        # 这句话作用是对传入的arg,进行调用my_sum/my_average
        return func(*arg)   

    return in_dec

my_sum = dec(my_sum) #此时返回的my_sum就是in_dec
my_sum(1,2,3,4,5)

my_average = dec(my_average) #此时返回的my_a verage就是in_dec
my_average(1,2,3,4,5)

闭包的作用:在函数中定义一个函数并返回该函数自身,用来处理数据。。

扫描二维码关注公众号,回复: 2214446 查看本文章

3.Python装饰器

装饰器:

  • 装饰器用来装饰函数
  • 返回一个函数对象
  • 被装饰函数标识符 指向 返回的函数对象(例如@dec返回的in_dex,使得my_sum=in_dec)
  • 语法糖 @deco

装饰器实质就是对闭包的一个使用。

-- 装饰器(就是对闭包的一种使用)
def dec(func):
    print('call dec')
    def in_dec(*arg): #my_sum、my_average作为func参数传入时,会成为in_dec函数的属性

        print('in dec arg=', arg)

        if len(arg) == 0;
            return 0
        for val in arg:
            if not ininstance(val,int)
            return 0

        return func(*arg)   

    return in_dec

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

-- 输出结果
call dec

@dec 
def my_sum(*arg):
    print('in my_sum')
    return sum(arg)

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

--输出结果
call dec
in dec arg = (1,2,3,4,5)
in my sum
15

装饰器自动执行@dec,调用dec这个函数,返回函数in_dec,被函数my_sum接收。

@dec 对应 dec(my_sum),返回函数in_dec
然后,此时my_sum = in_dec ,相对于上一节 my_sum = dec(my_sum)
然后此时my_sum()就是调用内部函数in_dec(),然后顺序执行,in_dec()内部的return func()其中就是func()就是my_sum(),因为函数调用时候my_sum()作为in_dec()一个属性保存了。

为什么要有return func(*arg)?
因为装饰器存在的目的是为本来要进行的函数(sum,average)进行包装,包装的意思一方面是多进行一些操作,另一方面是对一些函数具有想同逻辑的进行抽象,如果没有return操作,那就是包装袋里没有实物,就失去了本来的意义。

装饰器另一简单示例(基础示例,对于理解装饰器很有用):

def deco(func):
    def in_dec0():
        print ('in deco')
        func()
    print('call deco')
    return in_deco

@deco
def bar():
    print('in bar')

-- 输出结果
call deco

# 调用返回的bar()
bar()

-- 输出结果
in deco
in bar

函数运行过程如下:
这里写图片描述

可以看看这篇文章:https://blog.csdn.net/dreamcoding/article/details/8611578

def deco(func):
    def in_dec0(x,y):
        print ('in deco')
        func(x,y)
    print('call deco')
    return in_deco

@deco
def bar(x,y):
    print('in bar',x+y)

# 调用
bar(1,2)

-- 输出结果
in deco
in bar 3

第一步:deco(bar),返回一个对象in_deco
第二步:重新赋值 bar = in_deco
第三步:调用bar()时,实际上是调用in_deco()in_deco()处理时有用到bar()函数

猜你喜欢

转载自blog.csdn.net/u014465934/article/details/80993828