Python day10 闭包函数、装饰器

day10 闭包函数、装饰器

复习

函数对象

def func():  # func = 内存地址
    pass


print(func)
func()

函数嵌套定义

def outer():
    def wrapper():
        pass

    x = 100

名称空间与作用域

名称空间两大点

  1. 名字的访问顺序:LEGB
  2. 名称空间的嵌套关系是函数定义阶段扫描语法生成的,与调用位置无关

全局作用域:内置名称空间、全局名称空间

​ 特点:全局存活,全局有效

局部作用域:局部名称空间

​ 特点:临时存活,局部有效

global:用来在局部修改全局的不可变类型的值

dic = {'name': None}


def login():
    # dic = 123
    dic['name'] = 'egon'

login()
print(dic)

x = 100


def login():
    global x
    x = 200


login()
print(x)

nonlocal:修改上面的全局之下的不可变类型

def f1():
    x = 100

    def f2():
        nonlocal x
        x = 200

    f2()
    print(x)

f1()

1.闭包函数

  1. 闭函数:被封闭起来的函数==>定义函数内部的函数,闭函数的特点是只能在函数内用

    def outer():
        def wrapper():
            pass
    
  2. 包函数:该函数引用了一个名字,该名字是来自于E这一层

    def outer():
        x = 100
        def wrapper():
            print(x)
    

总结:闭包函数指的是定义在函数内部的函数引用了一个来自于外层函数作用域中的名字

闭包函数升级:结合函数对象

def outer():
    x = 100
    def wrapper():
        print(x)
    return wrapper

为函数体传参有两种解决方案

方案一:直接以参数的形式传入

def wrapper(x):
    print(x)
    
wrapper(100)

方案二:将函数包起来在外层传入专属参数,再将内层函数返回

def outer():
    x = 100
    def wrapper():
        print(x)
    return wrapper

def outer(x):
    def wrapper():
        print(x)
    return wrapper

f = outer(100)
print(f)

2.装饰器

  1. 什么是装饰器

    装饰器指的是装饰别人的工具,装饰指的则是为被装饰者添加新功能

    但是实现装饰器必须遵循的原则是"开放封闭原则"

    开放指的是对拓展功能是开放的,封闭指的则是对修改源码以及调用方式是封闭的

    综上:装饰器指的是创建一个工具,可以在尊旭原则1和2的前提下还能为被装饰对象添加新功能

    1. 不修改被装饰对象源代码

    2. 不修改被装饰对象的调用方式

  2. 为何要用装饰器

  3. 如何实现装饰器

    装饰器——>函数

    被装饰者——>函数

# 方案一:改变了被装饰者的源代码
import time

def index():
    start = time.time()
    print('from index')
    time.sleep(1)
    end = time.time()
    print(f'运行时长{end - start}')

index()

# 方案二:装饰器的功能需要重复编写,代码冗余
import time


def index():
    print('from index')
    time.sleep(1)

start = time.time()
index()
end = time.time()
print(f'运行时长{end - start}')

# 方案三:解决方案二代码冗余问题,但是存在问题,装饰器的功能写死了,只能装饰index函数
import time


def index():
    print('from index')
    time.sleep(1)

def wrapper():
    start = time.time()
    index()
    end = time.time()
    print(f'运行时长{end - start}')
    
# 方案四:装饰器功能写活
import time

def timer(func):
    def wrapper(*args, **kwargs):
        start = time.time()
        res = func(*args, **kwargs)
        end = time.time()
        print(f'运行时长{end - start}')
        print(func.__name__)
        return res

    return wrapper

#@timer
def index():
    print('from index')
    time.sleep(1)


index = timer(index) # !!!!!important  ==== @timer    


index()
print(index.__name__)
>>>>
from index
运行时长1.0015902519226074
index
wrapper

装饰器语法糖

@timer   # ==== index = timer(index)
def index():
    print('from index')
    time.sleep(1)

叠加多个装饰器

# 装饰器模板
def deco(func):
    def wrapper(*args,**kwargs):
        res = func(*args,**kwargs)
        return res
    return wrapper

# 统计时间装饰器
import time
def timer(func):
    def wrapper(*args,**kwargs):
        start = time.time()
        res = func(*args,**kwargs)
        end = time.time()
        print(f'{end-start}')
        return res
    return wrapper

# 认证功能装饰器
def auth(func):
    def wrapper(*args, **kwargs):
        username = input('输入用户名:').strip()
        pwd = input('输入密码:').strip()
        if username == 'egon' and pwd == '123':
            res = func(*args, **kwargs)
            return res
        else:
            print('登录失败')

    return wrapper
def deco1(func1):  # func1 = wrapper2的内存地址
    def wrapper1(*args, **kwargs):
        print('===>wrapper1')
        res1 = func1(*args, **kwargs)
        print('end ===>wrapper1')
        return res1

    return wrapper1


def deco2(func2):  # func2 = wrapper3的内存地址
    def wrapper2(*args, **kwargs):
        print('===>wrapper2')
        res2 = func2(*args, **kwargs)
        print('end ===>wrapper2')
        return res2

    return wrapper2


def deco3(func3):  # func3 = 最原始的index的内存地址
    def wrapper3(*args, **kwargs):
        print('===>wrapper3')
        res3 = func3(*args, **kwargs)
        print('end ===>wrapper3')
        return res3

    return wrapper3

    # index = wrapper1的内存地址


@deco1  # deco1(wrapper2的内存地址)  ———> wrapper1的内存地址
@deco2  # deco2(wrapper3的内存地址)  ———> wrapper2的内存地址
@deco3  # deco3(最原始那个index的内存地址) ———> wrapper3的内存地址
def index():
    print('====>index')


index()
>>>>
===>wrapper1
===>wrapper2
===>wrapper3
====>index
end ===>wrapper3
end ===>wrapper2
end ===>wrapper1

posted @ 2021-03-30 14:28  橘丶阳菜  阅读(40)  评论(0编辑  收藏  举报