学习python-Day15


今日学习内容

闭包函数简介

闭包函数

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

  2. 内部函数使用了外部函数名称空间里的名字

    def func():
        username = 'xz'  #形参接收实参
        def index():
            print(username)
        return index
    
    func()  #  func('xz')  相当于  username = 'xz'
    res = func()
    print(res) #<function func.<locals>.index at 0x000001CF915F8A60>
    res()
    
    #注意:外面的func运行后不会立马关闭,因为func内部还有函数,当后面的函数整个运行结束才结束。
    

闭包函数的实际应用

函数体代码传值的方式有2种

  • 形参

    def func(xxx)
    	print(xxx)
    
  • 闭包函数

    def index():
        username = 'xz'
    

def func():
         print(username)
     return func
 res = index()
 res()# xz
 
 def index(username):
     def func():
 print(username)
     return func
 res = index('xz')
 res()
 res1 = index('wyb')
 res1()

作用:可以在任意位置调用函数然后反复使用,注意的是当index重新输入一个实参,就会是原来和username绑定的数据值就会断开,重新绑定新的数据值 wyb。

image

装饰器简介

  1. 装饰器的本质

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

def func()
	print(123)
func()   #每次执行之前需要校验用户身份

  1. 装饰器的原则

    不能修改代码,只能扩展代码。

  2. 知识储备

    import time
    print(time.time()) #1657009750.2860615
    '''时间戳(秒数):当前距离1970年1月1日0时0分0秒'''
    time.sleep(3)
    '''让程序原地等待三秒'''
    print('3秒后我出来了!!!')
    
    
    

装饰器前期推导

  1. index前后加个时间戳,不影响调用方式内部代码

    import time
    def index():
        time.sleep(2)
        print('from index')
        
    '''统计index函数的执行时间'''
    start_time = time.time()  # 在调用index函数之前获取一下时间戳
    index()  # 调用index函数
    end_time = time.time()
    print('函数的执行时间是:', end_time - start_time)
    
    '运行结果:
    	from index
    	函数的执行时间是: 2.011164903640747'
    #这是没改变调用方式和内部代码,但是在面对多个index函数需要统计时间就很麻烦!!!
    """
    缺陷
        如果有多个index需要统计时间 则需要重复编写代码
        解决措施:
            封装成函数  def get_time()
    """
    
  2. 多个同一个函数需要统计时间,需要封装成函数

    '封装函数后'
    
    import time
    def index():
        time.sleep(2)
        print('from index')
        
    def get_time():
        start_time = time.time()  # 在调用index函数之前获取一下时间戳
        index()  # 调用index函数
        end_time = time.time()
        print('函数的执行时间是:', end_time - start_time)
    get_time()
    
    '运行结果:
    	from index
    	函数的执行时间是: 2.0149083137512207'
                    
    """
    缺陷
        如果有多个不同的函数需要统计时间 那么上述的解决措施不够完善
        解决措施: 
            给函数体添加形参(动态传参)  
    """
     
    
  3. 多个不同的函数需要统计时间,可以封装后用形参(动态传参)。

    import time
    def index():
        time.sleep(2)
        print('from index')
        
    def home():
        time.sleep(3)
        print('from home')
    
    def get_time(a):
        start_time = time.time()  # 在调用index函数之前获取一下时间戳
        a()  # 调用index函数,如果我们需要执行多个不同的代码可以引出一个变量名来代替函数名,这里需要添加实参为函数名,形参为变量名,然后就是将变量名和index函数名绑定,也就是将index赋值给左边的变量名。
        end_time = time.time()
        print('函数的执行时间是:', end_time - start_time)
    get_time(index)
    get_time(home)
    
    '运行结果:
    	from index
    	函数的执行时间是: 2.0056252479553223
    	from home
    	函数的执行时间是: 3.0146279335021973'
    
    """
    缺陷
        不同形参个数的函数无法兼容统计
        解决措施:
            *args  **kwargs
        但是在我们目前的代码中无法实现(暂且忽略)
    """
    

    image

  4. 不同形参函数的个数兼容统计(*args **kwargs)

    def home():
        time.sleep(5)
        print('from home')
    
    def get_time(xxx):
        start_time = time.time()  # 在调用index函数之前获取一下时间戳
        xxx()  # 调用index函数  #xxx(*args, **kwargs)会报错,因为代码没法识别括号里的东西是什么。
        end_time = time.time()
        print('函数的执行时间是:',end_time - start_time)
    # get_time(index)
    # get_time(home)
    
    
    """
    缺陷
        改变了原来的调用方式
        解决措施:
            装饰器推导流程
    """
    

装饰器各种版本

如果index或者home函数内有形参,则不能因形参的方式传值,而是用闭包函数来做。

def outer(xxx):
    def get_time():
        start_time = time.time()
        xxx() #调用index函数
        end_time = time.time()
        print('函数的执行时间是:', end_time - start_time)
    return get_time
res = outer(index) #
res()#get_time()

res1 = outer(home)
res1()

'运行结果:
    from index
    函数的执行时间是: 2.0112996101379395
    from home
    函数的执行时间是: 3.0021297931671143'
       
    

image

还是不符合装饰器的条件,不满足调用方式。

所以我们可以改变变量名。

def outer(xxx):
    def get_time():
        start_time = time.time()
        xxx() #调用index函数
        end_time = time.time()
        print('函数的执行时间是:', end_time - start_time)
    return get_time
index = outer(index) #
index()#get_time()

home = outer(home)
home()

image

import time
def index(name):
    time.sleep(2)
    print('from index')

def home():
    time.sleep(3)
    print('from home')
"""针对有参无参函数如何兼容"""
def outer(a):
    def get_time(*args, **kwargs):
        start_time = time.time()  # 在调用index函数之前获取一下时间戳
        res = a(*args, **kwargs) # 调用index函数
        end_time = time.time()
        print('函数的执行时间是:', end_time - start_time)
		return res
    return get_time
index = outer(index)
index('xz')
xxx = index #index为outer函数返回结果get_time.赋值给左边
print(xxx) #get_time  的内存地址

'运行结果:
    from index
    函数的执行时间是: 2.0117368698120117
    <function outer.<locals>.get_time at 0x0000026EA19D8B80>'

image

装饰器的固定模板

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

inner = outer()
inner()


装饰器语法糖
# 装饰器语法糖
import time
#将紧挨着这个语法糖的函数名当做函数的参数赋值给变量名
@outer  #  home = outer(真正的函数名home)
def home():
    '''我是home函数 我要热死了!!!'''
    time.sleep(1)
    print('from home')
    return 'home返回值'

help
# help(home)
# print(home)
home()

def index():
    '我是index函数 我的功能很强大'
    pass

help(index)

#帮助我们知道括号内的函数内容是什么,有些需要该函数上加个from functools import wraps    函数内加个#@wraps(func_name)  # 仅仅是为了让装饰器不容易被别人发现 做到真正的以假乱真

作业

1.编写一个用户认证装饰器
基本要求
执行每个函数的时候必须先校验身份 eg: jason 123
拔高练习(有点难度)
执行被装饰的函数 只要有一次认证成功 那么后续的校验都通过
函数:register login transfer withdraw
提示:全局变量 记录当前用户是否认证

def login():
    print('登录成功!')
    return

def outer(login_func):
    def func(*args,**kwargs):
            username = input('请输入用户名>>>:').strip()
            password = input('请输入密码>>>:').strip()
            if username == 'xz' and password == '123':
                res = login_func(*args,**kwargs) #login函数的返回值
                return res  # func的函数返回值为res
            else:
                print('登录失败!')
    return func
login= outer(login)
login()

原创文章,作者:carmelaweatherly,如若转载,请注明出处:https://blog.ytso.com/272996.html

(0)
上一篇 2022年7月9日
下一篇 2022年7月9日

相关推荐

发表回复

登录后才能评论