python-函数(3)

内容概览

  • 闭包函数简介
  • 闭包函数应用
  • 装饰器简介
  • 装饰器推导过程
  • 装饰器各种版本
  • 装饰器模板

闭包函数

  • 闭包函数简介

    什么是闭包函数:
    1. 定义在函数内部的函数
    2. 内部函数使用了外部函数的名称空间的名字
    3. 外函数的返回值是内函数名
      符合以上三个条件才能称作闭包函数
    def fn():
    	num = 1
    	def fn1():
    		print(num)
    	return fn1
    
    res = fn()  # 将fn的返回值fn1赋值给res,res就等同于fn1
    res()  # 1  
    
  • 闭包函数的应用

    """既然要使用的是外层函数名称空间的名字,那也可以使用传入的参数,这样使代码更加灵活"""
    def fn1(s):  # 传入的实参和形参临时绑定存放在局部名称空间中
    	def fn2():
    		print(s)
    	return fn2
    	
    res = fn1(123)  # 这样就能传入想打印的任何值
    res()  # 123
    
    
    """函数也是可以当做实参传入函数中"""
    def fn():
    	print('函数fn')
    
    def outer(function):
    	print('函数outer')
    	def inner():
    		print('函数inner')
    		function()  # 调用传入的函数
    	return inner
    
    res = outer(fn)  # 函数outer  这里将fn函数名当做参数传入outer函数,执行outer函数体代码
    res()  # 函数inner 函数fn  执行inner函数体代码
    """闭包函数也是用来给函数传参的方式"""
    

装饰器

  • 装饰器简介

    装饰器就是涵盖了多种函数知识的特殊的使用方法
    1. 装饰器的本质:
      在不改变被装饰对象的调用方式与内部代码的情况下给被装饰对象增加新的功能
    2. 装饰器的原则:
      对修改封闭,对扩展开放
  • 装饰器的推导过程

    import time
    # 先导入时间模块
    
    def fn():
    	time.sleep(1)
    	print('fn函数')
    """如果需要计算fn函数的执行时间"""
    start_time = time.time()  # 获取时间戳
    fn()
    end_time = time.time()
    print(end_time - start_time)  # 1.0020077228546143
    """
    这样些的话,想要多次统计fn函数执行时间都要写重复的代码
    所以可以把这串代码封装成函数
    """
    def get_time():
    	start_time = time.time()
    	fn()
    	end_time = time.time()
    	print(end_time - start_time)
    
    get_time()  # 每次需要统计fn执行时间只需要调用get_time即可
    """
    这样虽然解决了多次使用相同代码的问题,但只能统计fn函数的执行时间,如果想要统计其他函数的执行时间呢
    将需要统计的函数使用传参的方式传入即可
    """
    def new_get_time(func):
    	start_time = time.time()
    	func()
    	end_time = time.time()
    	print(end_time - start_time)
    
    def fn1():
    	time.sleep(3)
    	print('fn1函数')
    
    new_get_time(fn)  # fn函数 1.0145471096038818
    new_get_time(fn1)  # fn1函数 3.0013294219970703	
    
    """
    这样就可以计算不同函数的执行时间了
    可如果有函数需要传参,没有参数传入就会报错
    而且调用函数的方式也变成了调用新的函数
    为了解决这些问题,就需要用到装饰器模式了
    """
    
  • 装饰器各种版本

    import time
    """对于不同函数有无参数的兼容"""
    def outer(function):
    	def inner(*args, **kwargs):  # 接收传入的多余的参数
    		start_time = time.time()
    		function(*args, **kwargs)  # 将容器类型的数据类型拆分开一次性当做参数传入
    		end_time = time.time()
    		print(end_time - start_time)
    	return inner
    
    def fn1():
    	time.sleep(1)
    	print('fn1')
    
    def fn2(a):
    	time.sleep(3)
    	print('fn2')
    
    fn1 = outer(fn1)  # 这里fn1已经传入了outer,重新使用fn1绑向新的函数名,做到调用方式不变
    fn1()
    fn2 = outer(fn2)
    fn2(1)
    """这样写对于有无参数的兼容就做完了,可是如果有返回值这样还是拿不到,因为我们调用的实际上是inner,inner没有设置返回值"""
    def outer(function):
    	def inner(*args, **kwargs):  
    		start_time = time.time()
    		res = function(*args, **kwargs)  # 接收返回值
    		end_time = time.time()
    		print(end_time - start_time)
    		return res  # 将函数返回值原封不变的返回
    	return inner
    
    def fn1():
    	time.sleep(1)
    	print('fn1')
    	return 123
    
    def fn2(a):
    	time.sleep(3)
    	print('fn2')
    	return 321
    
    fn1 = outer(fn1) 
    res = fn1()
    print(res)  # 123
    fn2 = outer(fn2)
    res = fn2(1)
    print(res)  # 321
    """
    装饰器语法糖
    在需要被装饰的函数上一行代码加上@+装饰器
    """
    @outer  # 这句等同于fn2 = outer(fn2)
    def fn2():
    	time.sleep(1)
    	print('fn2')
    
    fn2()
    
  • 装饰器的模板

    from functools import wraps
    def outer(func_name):
    	@wraps(func_name)  # 只是为了让别人不容易发现这个函数被装饰过
    	def inner(*args, **kwargs):
    		print('被装饰对象执行前可添加的功能')
    		res = func_name()
    		print('被装饰对象执行后可添加的功能')
    		return res
    	return inner
    
    @outer
    def fn():
    	pass
    
    print(fn)  # <function fn at 0x000001CFA02CBA60>
    

练习

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

user_dict = {'xm': '123', 'xh': '321'}
flag = 0

while True:
    def outer(function):
        @wraps(function)
        def inner(*args, **kwargs):
            global flag
            if not flag:
                user_name = input('请输入用户名:').strip()
                if user_name not in user_dict:
                    print('用户不存在')
                    return
                pass_word = input('请输入密码:').strip()
                if not user_dict[user_name] == pass_word:
                    print('密码错误')
                    return
            res = function(*args, **kwargs)
            flag = 1
            return res
        return inner


    @outer
    def register():
        print('注册功能')


    @outer
    def login():
        print('登录功能')


    @outer
    def transfer():
        print('转账功能')


    @outer
    def withdraw():
        print('取款功能')


    func_dict = {'1': register, '2': login, '3': transfer, '4': withdraw}
    choise = input("""
            1.注册
            2.登录
            3.转账
            4.取钱
            请选择:
    """).strip()
    if choise in func_dict:
        func_dict[choise]()
    else:
        print('输入有误')
        
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值