Python之闭包 装饰器

函数的闭包

 

1. 函数的嵌套调用

def func():
    print(123)

def func2():
    func()
    print(234)

func2()

 

2. 函数的嵌套定义

def func():
    print(123)
    def func2():
        print(234)

    func2()    # 只能在func里面调用func2

func()

 

3. 闭包

  a.  闭包本质就是一种函数

  b.  使用闭包一定会使用到嵌套函数

  c.  闭包的意义:在变量不被别人调用的时候,最大的节省空间

  d.  内部函数引用了外部函数的变量,内部函数就叫闭包

def func():
    name = "chita"
    def inner():        # inner就是闭包函数
        print(name)

    print(inner.__closure__)  # 检测是不是闭包,是的话打印(<cell at 0x000001F9F5760108: str object at 0x000001F9F58564C8>,) 不是的话打印 none

ret = func()
ret()

 

装饰器

1.  装饰器其本质就是闭包,是特殊的闭包函数

def func():
    def inner():    # inner是闭包
        print('inner')
    return inner

# 整个func函数就是装饰器

 

2. 装饰器的作用

  a. 在一个函数的前后添加功能,不能修改函数的信息,并且对于用户感知不到装饰器的存在

  b. 开放封闭原则, 即扩展是开放的,修改是封闭的

 

3.  常见装饰器

  a. 被装饰函数没有参数

import time


def timmer(func):  
    def inner():
        start = time.time()
        func()
        end = time.time()
        print(end-start)
    return inner


@timmer    # 语法糖  其本质就是先执行 qqxing = timmer(qqxing),然后执行qqxing()
def qqxing():    # 被装饰的函数
    for i in range(10000000):pass
    print("老板万岁")


qqxing()

   b. 被装饰函数有参数

import time


def timmer(func):    
    def inner(*args,**kwargs):
        start = time.time()
        ret = func(*args,**kwargs)  #qqxing
        end = time.time()
        print(end-start)
        return ret
    return inner

@timmer    # 语法糖  等价于qqxing = timmer(qqxing)
def qqxing(num1,num2):    # 被装饰的函数
    for i in range(10000000):pass
    print("老板万岁")
    return num1,num2

ret = qqxing(2,5)
print(ret)

 

  c. 最简单的装饰器

def wrapper(func):#装饰器
    def inner(*args,**kwargs):
        print("被装饰的函数执行之前你要做的事")
        ret = func(*args,**kwargs) #func是被装饰的函数 :参数,返回值
        print("被装饰的函数执行之后你要做的事")
        return ret
    return inner

 

  d. 带参数的装饰器

FLAG = False


def log(flag):
    def wrapper(func):
        def inner(*args,**kwargs):
            if flag:
                print("call :%s"%func.__name__)
            ret = func(*args,**kwargs)
            return ret
        return inner
    return wrapper

@log(FLAG)  #  @和log(FLAG)是分开执行的,一般都是从后往前执行
# 执行流程: wrapper =log(FLAG)
# @wrapper-->qqxing = wrapper(qqxing)--->qqxing=inner

def qqxing():
    print("qqxing")

qqxing()    # qqxing()=inner()

 

   e. 嵌套装饰器

def wrapper1(func):
    def inner1():
        print('wrapper1 ,before func')
        func()  # f
        print('wrapper1 ,after func')
    return inner1

def wrapper2(func):
    def inner2():
        print('wrapper2 ,before func')
        func()   # inner1
        print('wrapper2 ,after func')
    return inner2

@wrapper2   # f = wrapper2(wrapper1(f))  --> f = wrapper2(inner1)   -->   f = inner2
@wrapper1   # 谁先被调用的谁在外边,一般都是从后往前执行
def f():
    print('in f')


f()     # inner2()

  结果:

  now in wrapeer2,before func
  now in wrapeer1,before func
  now in func
  after func 1
  after func 2

分析:    

  当程序运行到上面两句的时候只是执行了以下几步:

    首先执行的是@wrapper1---->func=wrapper(func)

    然后等到执行的@wrapper2,此时的func=wrapper(func),所以这步的结果是func=wrapper2(wrapper1(func))

  执行到func()的时候:
    func()被调用,此时的func=wrapper2(wrapper1(func))的结果是func=inner2,所以func()等价于inner2()
    在inner2函数中,执行到func()的时候,此时的func=wrapper(func),即func=inner1,所以此时调用的是inner1()
    在inner1函数中,执行到func()的时候,此时的func=func,所以是执行func()自己,
    inner1执行完毕后,回到inner2中继续执行,然后结束

 

 

 

 

 

 

 

 

posted @ 2018-11-25 10:00  chitalu  阅读(169)  评论(0编辑  收藏  举报