闭包函数和装饰器

闭包函数简介

闭包函数:
	1.定义在函数内部的函数
  2.内部函数使用了外部函数名称空间的名字
ps: 只有上述两个特征的函数才能称之为闭包函数

def func(username):
    def index():
        print(username)
    return index
res = func('jason')
res()  #
'''
1.先执行func('jason)函数
2.再执行index()函数,返回index函数名给变量res
3.res()就等于是index(),执行index函数内代码
'''

装饰器简介

"""
装饰器不是一个全新知识,而是我们前面的函数知识的整合
"""
1.装饰器的本质
	在不改变被装饰对象原来的'调用方式'和'内部代码'的情况下给被装饰对象添加新的功能
  eg:
    def func():
			print(123)
    func()   # 每次执行之前需要校验用户身份
 2.装饰器的原则
	 对修改封闭,对扩展开放
 3.知识储备
    import time
    print(time.time())  # 1657005080.087934
    '''时间戳(秒数):当前距离1970年1月1日0时0分0秒的距离'''
    # 实际运用 >>>:统计代码的运行时间
    start_time = time.time()
    for i in range(10000):
        print(i)
    end_time = time.time()
    print('for循环10000次的执行时间是:%s' % (end_time-start_time) )  # for循环10000次的执行时间是:0.026255130767822266
    time.sleep(3)  # 让程序原地等待三秒

装饰器前期推导

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

'''1.统计index函数的执行时间'''
# start_time = time.time()
# index()
# end_time = time.time()
# print(end_time-start_time)
'''
缺陷: 如果有多个index需要统计时间,则需要重复编写
      解决措施:
        封装成函数
'''
#
# def get_time():
#     start_time = time.time()
#     index()
#     end_time = time.time()
#     print(end_time-start_time)
# get_time()
'''
缺陷: 如果有多个不同的函数需要统计时间,那么上述的解决措施不够完善
      解决措施:
        给函数体添加形参(动态传参)
'''
# def home():
#     time.sleep(5)
#     print('from home')
#
# def get_time(xxx):
#     start_time = time.time()
#     xxx(*args,**kwargs)
#     end_time = time.time()
#     print(end_time-start_time)
# get_time(index)
# get_time(home)
'''
缺陷:不同行参个数的函数无法兼容统计
      解决措施:
        *args,**kwargs
      但是在外面目前的代码中无法实现(暂且忽略)
'''
# 
# def func1(a):
#     time.sleep(1)
#     print('from func1')
# get_time(func1)
'''
缺陷: 改变了原来的调用方式
      解决措施:
        装饰器推导流程
'''

装饰器各种版本

""" 针对有参无参函数如何兼容 """
import time
def outer(xxx):
    def get_time(*args,**kwargs):
        start_time = time.time()
        res = xxx(*args,**kwargs)  # from home     # from index
        end_time = time.time()
        print(end_time-start_time)  # 2.0044140815734863  # 3.0019779205322266
        return res
    return get_time

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

home = outer(home)
res1 = home()
print(home)  # <function outer.<locals>.get_time at 0x10285be50>  # 执行index函数之后的返回值

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

装饰器固定模版

from functools import wraps
import time
def outer(func_name):
    @wraps(func_name)
    def inner(*args,**kwargs):
        print('执行被装饰对象之前可以做的额外操作')
        res = func_name(*args,**kwargs)
        print('执行被装饰对象之后可以做的额外操作')
        return res
    return inner
# def home():
#     time.sleep(1)
#     print('from home')
#     return 'home返回值'
# home = outer(home)
# res = home()
# print(res)

"""
执行home函数之前需要添加校验用户身份的功能
"""

# 装饰器语法糖
@outer
def home():
    '''我是home函数'''
    time.sleep(1)
    print('from home')
    return 'home返回值'
home()
# home = outer(home)
# print(home)  # <function home at 0x10f436e50>

案例

"""
1.编写一个用户认证装饰器
  基本要求
   执行每个函数的时候必须先校验身份 eg: jason 123
  拔高练习(有点难度)
   执行被装饰的函数 只要有一次认证成功 那么后续的校验都通过
     函数:register login transfer withdraw
   提示:全局变量 记录当前用户是否认证
"""
from functools import wraps
login_result = ''  # 全局变量 判断是否登录成功
def outer(func_name):
    @wraps(func_name)
    def inner(*args,**kwargs):
        if login_result == '登录成功':
            ret = func_name(*args,**kwargs)
            return ret
        else:
            print('未登录无访问权限')
    return inner
def register():
    username = input('请输入注册用户名>>>:').strip()
    with open(r'user_info','r',encoding='utf8') as file:
        for line in file:
            if line.strip() != ''.strip():  # 判断文件内是否为空,如不进行判断,下面解压赋值会报错
                real_name, real_pwd = line.strip().split('|')
                if username == real_name:
                    print('该用户名已经注册!')
                    break
                else:
                    password = input('请输入注册密码>>>:').strip()
                    user_info = f'{username}|{password}\n'
                    with open(r'./user_info', 'a', encoding='utf8') as file1:
                        file1.write(user_info)
                        file1.flush()
                        print('注册成功')
                        break
            else:
                password = input('请输入注册密码>>>:').strip()
                user_info = f'{username}|{password}\n'
                with open(r'./user_info', 'a', encoding='utf8') as file1:
                    file1.write(user_info)
                    file1.flush()
                    print('注册成功')
                    break
def login():
    username = input('请输入登录账号>>>:').strip()
    password = input('请输入登录密码>>>:').strip()
    user_info = f'{username}|{password}'
    with open(r'./user_info','r',encoding='utf8') as file:
        for line in file:
            global login_result

            if user_info == line.strip():
                login_result = '登录成功'
                print('登录成功')

                global name_book
                name_book = username
                break
        else:
            # result = '登录失败'
            print('用户名或者密码错误')
import os
@outer
def transfer():  # 只能本人转账给他人,简单实现
    name = input('请输入转账人')
    money = input('请输入转账金额')
    with open('./books','r',encoding='utf8') as file:
        item_book ={}
        for line in file:
            real_name,real_money = line.strip().split('|')
            if real_name not in item_book:
                item_book[real_name] = real_money
    if name in item_book:
        with open(r'./books','r',encoding='utf8') as file:
            info = file.read()
        modify_info = f'{name_book}|{item_book.get(name_book)}'
        modify_other = f'{name}|{item_book.get(name)}'
        my_money = int(item_book.get(name_book))- int(money)
        other_money = int(item_book.get(name)) + int(money)
	print(f'您转账给{name}{money}元,余额为:{my_money}')
        with open(r'./books','r',encoding='utf8') as file1, open (r'./demo.txt.swap','w',encoding='utf8') as file2:
            for line in file1:
                if line.strip() == modify_info:
                    file2.write(line.replace(modify_info,f'{name_book}|{my_money}'))
                if line.strip() == modify_other:
                    file2.write(line.replace(modify_other,f'{name}|{other_money}'))
    os.remove('books')
    os.rename('./demo.txt.swap','books')
@outer
def withdraw():
    print('退出登录成功,请重新登录')
    is_withdraw = input('确认要退出登录吗?y 确定退出 ').strip()
    global login_result
    if is_withdraw == 'y':
        login_result = ''
    return
func_dict = {
    '1':register,
    '2':login,
    '3':transfer,
    '4':withdraw
}
while True:
    print("""
    1.注册功能
    2.登录功能
    3.转账功能
    4.退出登录功能
    
    """)
    func_id = input('请输入功能编号')
    if func_id in func_dict:
        res = func_dict.get(func_id)
        res()
posted @ 2022-07-05 16:13  荀飞  阅读(7)  评论(0编辑  收藏  举报