闭包函数、装饰器基础学习01

闭包函数简介

闭包函数:要满足以下俩个函数才能称之为闭包函数

1.定义在函数内部的函数

2.内部函数使用了外部函数名称空间中的名字
username = 'jason'
def func():
    def index():
        print(username)
'''
问题:函数index()是不是闭包函数?
    不是,print(username)里面的username用的是全局名称空间里的
'''
def func():
    username = 'jason'
    def index():
        print(username)
'''此时就是闭包函数了'''
'''
思考如何在全局调用index?
思考过程:
def func():
    username = 'jason'
    def index():
        print(username)
    return 123
返回的是123
def func():
    username = 'jason'
    def index():
        print(username)
    return username
返回的是username所绑定的值jason
def func():
    username = 'jason'
    def index():
        print(username)
    return index
res = func()
print(res)   # <function func.<locals>.index at 0x0000020793F87790>
返回的是函数名,此时res就是绑向内存空间里的函数体代码的内存地址,此时它跟函数名一样了,那么调用函数加个()也就可以了
'''
'''从全局用局部名称空间的值'''
def func():
    username = 'jason'
    def index():
        print(username)
    return index
res = func()
res()  # jason
'''如果是这样的话,还是不是闭包函数'''
def func(username):
    # username = 'jason'
    def index():
        print(username)
    return index
func('jason')
'''
解释:在调用阶段,形参和实参回临时绑定,就是在调用的时候其实已经发生了将Jason绑定给username了,那么此时func局部名称空间就会有名字出现
    因此也符合闭包函数的定义
'''

闭包函数的实际应用

def func(username):
    # username = 'jason'
    def index():
        print(username)
    return index
func('jason')
'''
在局部空间里又存在着局部空间的时候,原来所说的局部空间在函数体代码运行的时候开启在函数体代码结束时关闭,那么这个时候在这种情况下会有所不同
当func()运行的时候他是不会关的,因为它检测到后面index()里还需要使用,它会一直开启着直到里面的那个局部名称空间关闭以后才会关闭
'''

image-20220705161718418

'''给函数体代码传值的方式1:通过形参'''
def func(XXX):
    print(XXX)
'''给函数体代码传值的方式2:闭包函数'''
def index(username):
    # username = 'jason'  # 这么写的话就写死了
    def func():
        print(username)
    return func
# res = index()  # res就是func
# res()  # 就是func(),后面就可以反复的调用res()
res = index('jason')
res()
res1 = index('kevin')
'''
1.内置名称空间的创建
2.全局名称空间(index)
3.index('jason'),函数名加括号执行优先级最高,执行index()函数的调用,将jason传给username
4.index()局部名称空间创建(username绑定jason、func())
5.func返回到全局名称空间里到了res里
6.函数名res加括号,res()=func(),调用func()函数
7.func()函数里要找username,本局部名称空间里没有,找上一层里的找到了jason
'''

装饰器简介

1.装饰器的本质

在不改变被装饰对象 [原来的调用方式] 和 [内部代码] 的情况下给被装饰对象添加新的功能

2.装饰器的原则

对修改封闭 对扩展开放

3.知识储备

import time
print(time.time())  # 1657011706.287414
'''时间戳(秒数):当前距离1970年1月1日0时0分0秒所经历的秒数'''
time.sleep(4)
'''
让程序原地等待四秒
数字控制着秒数,就是在程序在几秒之后运行出结果
'''
print('123456')

装饰器推导流程

import time
print(time.time())  # 1657011706.287414
'''时间戳(秒数):当前距离1970年1月1日0时0分0秒所经历的秒数'''
time.sleep(4)
'''
让程序原地等待四秒
数字控制着秒数,就是在程序在几秒之后运行出结果
'''
print('123456')

# 统计代码的运行时间
# start_time = time.time()  #  100
# for i in range(100000):
#     print(i)
# end_time = time.time()
# print('for循环的执行时间是:%s'%(end_time - start_time))

def index():
    time.sleep(2)
    print('from index')
start_time = time.time()  # 在调用index函数之前获取一下时间戳
index()  # 调用index函数
end_time = time.time()
print(end_time - start_time)
'''
如果要多次调用index()
那每次都会调用它前后的代码
start_time = time.time()  # 在调用index函数之前获取一下时间戳
index()  # 调用index函数
end_time = time.time()
print(end_time - start_time)
这个样子的话就会在每次调用都得写这几行代码
 缺陷1:
     如果有多个index得需要统计时间,则需要重复编写代码
     解决措施:封装成函数
'''
def get_time():
    start_time = time.time()  # 在调用index函数之前获取一下时间戳
    index()  # 调用index函数
    end_time = time.time()
    print('函数得执行时间是:', end_time - start_time)
'''
缺陷2:
    如果有多个不同的函数需要统计时间,那么上述的解决措施不够完善
    解决措施:给函数体添加形参(动态传参)
'''
def home():
    time.sleep(3)
    print('from home')
def get_time(xxx):
    start_time = time.time()  #
    xxx()  # 调用index函数
    end_time = time.time()
    print('函数得执行时间是:', end_time - start_time)
get_time(index)
get_time(home)
'''
缺陷3:
    不同形参个数的函数无法兼容统计
    解决措施:*args,**kwargs,但是在目前无法实现
'''
def home():
    time.sleep(3)
    print('from home')
def get_time(xxx):
    start_time = time.time()  #
    xxx()  # 调用index函数
    end_time = time.time()
    print('函数得执行时间是:', end_time - start_time)
def func1(a):
    time.sleep(1)
    print('from func1')
get_time(func1())
'''
缺陷4:
    改变了原来的调用方式
    解决措施:*args,**kwargs,但是在目前无法实现
            使用闭包函数
'''
def index():
    time.sleep(2)
    print('from index')
def home():
    time.sleep(3)
    print('from home')
def outer(xxx):
    # xxx = index
    def get_time():
        start_time = time.time()  # 在调用index函数之前获取一下时间戳
        xxx()
        end_time = time.time()
        print('函数的执行时间是:', end_time - start_time)
    return get_time
# res = outer(index)
# print(res)  # <function outer.<locals>.get_time at 0x000002570FBD7820>
# res()
# res1 = outer(home)
# print(res1)  # <function outer.<locals>.get_time at 0x000002570FBD78B0>
# res1()
'''
1.定义一个函数outer(),不会立刻关掉
2.然后将函数名index赋值给outer函数的形参XXX
3.定义一个函数get_time(),返回get_time,用变量名res接收get_time
4.res()=get_time(),然后执行index()
'''
index = outer(index)
index()
home = outer(home)
home()
'''
1.定义一个函数outer(),不会立刻关掉
2.然后将正真的函数名index函数名赋值给outer局部名称空间中的形参XXX
3.定义一个函数get_time(),返回get_time,用变量名res接收get_time
4.用一个函数名(与正真index函数名一致)去接收get_time
5.
'''

装饰器争对有参无参函数如何兼容

import time
"""针对有参无参函数如何兼容"""
def outer(xxx):
    def get_time(*args, **kwargs):
        start_time = time.time()
        xxx(*args, **kwargs)  # 依次取出*号后面的数据类型的值,一次性传给它  funv('jason')
        end_time = time.time()
        print('函数的执行时间是:', end_time - start_time)
        return res
    return get_time

def home():
    time.sleep(2)
    print('from home')
    return '执行home函数之后的返回值'

def index(name):
    time.sleep(1)
    print('from index')
    return '执行index函数之后的返回值'

index = outer(index)
res = index('jason')
print(res)

home = outer(home)
home()

def func(a,b,c):
    time.sleep(1)
    print('from func')

index = outer(index)
index('jason')

home = outer(home)
home()

func = outer(func)
func(1,2,3)

import time
def outer(xxx):
    def get_time(*args, **kwargs):
        start_time = time.time()
        res = xxx(*args, **kwargs)  # 依次取出*号后面的数据类型的值,一次性传给它  funv('jason')
        end_time = time.time()
        print('函数的执行时间是:', end_time - start_time)
        return res
    return get_time

def home():
    time.sleep(2)
    print('from home')
    return '执行home函数之后的返回值'

def index(name):
    time.sleep(1)
    print('from index')
    return '执行index函数之后的返回值'

home = outer(home)
xxx = home()
print(xxx)  # None

index = outer(index)
res = index('jason')
print(res)

装饰器固定模板与语法糖

'''
1.首先先写一个外层函数
2.里面再写一个函数
3.如果要给一个函数装一个装饰器的话,函数写写好,然后 函数 = 外层函数名(函数),res = 函数(),打印res
4.函数 = 外层函数名(函数),可以用语法糖替代
'''
from functools import  wraps
def outer(func_name):
    @wraps(func_name)  # # 是为了让装饰器不容易被别人发现,做到真正的以假乱真,不会影响代码,写不写都可以
    def inner(*args, **kwargs):
        print('执行被装饰对象之前可以做的额外操作')
        res = func_name(*args, **kwargs)
        print('执行被装饰对象之后可以做的额外操作')
        return res
    return inner
'''怎么用??'''
import time
def home():
    time.sleep(1)
    print('from home')
    return 'home返回值'

home = outer(home)  # 装饰器特殊用法
res = home()
print(res)
'''
执行被装饰对象之前可以做的额外操作
from home
执行被装饰对象之后可以做的额外操作
home返回值

执行home函数之前需要添加校验用户身份的功能
def outer(func_name):
    def inner(*args, **kwargs):
        username = input('username:').strip()
        password = input('password:').strip()
        if username == 'jason' and password == '123':
            res = func_name(*args, **kwargs)
            return res
        else:
            print('权限不够')
    return inner
    
username:jason
password:123
from home
home返回值
    
username:zhanran
password:123
权限不够
None
'''

'''
装饰器语法糖
    如果想给一个函数装一个装饰器,只需要在函数的上面加一个@outer(=(home = outer(home)))
'''
# import time
# @outer
# def home():
#     time.sleep(1)
#     print('from home')
#     return 'home返回值'
# print(home)  # <function outer.<locals>.inner at 0x000002A1578E70D0>

def index():
    '我是index函数'
    pass
help(index)
'''
Help on function index in module __main__:

index()
    我是index函数
ps:help就是可以提示括号里的东西有哪些核心的数据
'''

posted @ 2022-07-05 21:47  张张包~  阅读(60)  评论(0编辑  收藏  举报