装饰器

今日内容概要

  • global与nonlocal
  • 函数名的多种用法
  • 闭包函数
  • 装饰器简介
  • 无参装饰器

global 与nonlocal

  • golobal 改变全局变量

  • nonlocal 改变外层局部名称空间的变量

函数名的多种用法

  1. 可以当成实参

    # 可以当成实参传递
    def index(xx):
        print(xx)
    
    def func():pass
    
    
    index(func)
    
  2. 可以放到容器里面

    def login():
        print("登录")
    
    
    def register():
        print("注册")
    
    
    def select():
        print("查看")
    
    
    data_dict = {
        "1": login,
        "2": register,
        "3": select,
        "4": exit
    }
    
    while True:
        print("""
        1.登录
        2.注册
        3.查看
        4.退出
        """)
        choice = input("请输入编号:").strip()
        if not choice.isdigit():
            print("请输入数字")
            continue
        if choice not in data_dict:
            print("编号不存在")
        data_dict.get(choice)()
    
    
  3. 可以被赋值给别的变量名

    def func():
        print("哈哈")
    
    res = func
    res()
    
  4. 可以当作返回值

    def func():
        print("哈哈")
        return func
    
    res = func()
    res()
    

闭包函数

内部函数可以引用外层函数的名字

闭包函数的应用就是

"""定义到内部的函数用到外部函数中的名字"""


def index():
    name = "jason"

    def func():
        print(name)


"""闭包函数"""

装饰器简介

  1. 在不改变原函数体代码及调用方式的情况下,为原函数添加新的功能

    • 条件

      1.不改变原函数体代码
      2.不改变原函数体的调用方式

    • 结果

      添加新的功能

  2. 本质

    并不是一门新的技术 而是由函数参数、名称空间、函数名多种用法、闭包函数组合到一起的结果

  3. 口诀

    对修改封闭 对扩展开放

    解释:对修改内部代码和调用方式不行,我原有的你不能动, 但是你可以扩展我的功能

  4. 储备知识

    # 时间操作
    import time
    
    # print(time.time())  # 1665476504.078971
    # 打印出来的是时间戳 是计算机元年到当前时间过去了多少秒
    # 计算机元年 一九七零年一月一日零时零点零分 1970.01.01 00:00:00
    # time.sleep(3)
    # print("哈哈哈")
    
    count = 0
    start_time = time.time()
    while count < 10000:
        # print(1)
        count += 1
    end_time = time.time()
    print("消耗时间", end_time - start_time)
    

装饰器推导流程

""""
在不改变原函数体代码及调用方式的情况下,为原函数添加新的功能
条件 1.不改变原函数体代码
     2.不改变原函数体的调用方式
结果 添加新的功能
"""
import time


# 原函数
# def index():
#     print("from index")
# index()
# 需求添加计时器功能 就是计算运行时间

# 因为函数定义阶段不能动 所以只能动调用阶段
# import time
# def index():
#     print("from index")
#
# start = time.time()
# index()
# time.sleep(0.3)
# end = time.time()
# print(end - start)

# 虽然实现了 但是  
# 每次调用都得重新写一遍

# 重新写一遍 重新写一变 代码的重用
# 1. 循环 2.函数  有这两种方式的实现 而我们需要在不同的位置重用代码
# 所以我们选择函数  把代码缩进 进去 

# def index():
#     print("from index")
#
# def inner():
#     start = time.time()
#     index()
#     time.sleep(0.3)
#     end = time.time()
#     print(end - start)
# inner(index)

# 虽然实现了但是原函数写死了 现在只能统计index的执行时间了  

# 不就原函数写死 我把他提上去 变成形参

# def index():
#     print("from index")
# 
# def inner(xxx):
#     start = time.time()
#     xxx()
#     time.sleep(0.3)
#     end = time.time()
#     print(end - start)
# inner(index)

# 但是条件不符合  调用方式改变了
# 因为是在传参的时候遇到了问题所以  这种传参pass
# 但是我们学了两种传参方式既然这种不行那就换一种
# 闭包
# 闭包的定义  在内部函数引用外部函数的名字
# def index():
#     print("from index")
#
# def outer(xxx):
#     def inner():
#         start = time.time()
#         xxx()
#         time.sleep(0.3)
#         end = time.time()
#         print(end - start)
#     return inner
#
# index = outer(index)
# indexr()

index = outer(index)

outer(index) = inner

# 这只是如果原函数是无参函数的时候
# 当有参函数的时候怎么办
# 就可以用可变长形参和可变长实参来接收 和传递

# def index(aa, ):
#     print("from index", aa)
#
#
# def outer(xxx):
#     def inner(*args, **kwargs):  # 他是怎么接的
#         start = time.time()
#         xxx(*args, **kwargs)  # 我就是怎么传的
#         time.sleep(0.3)
#         end = time.time()
#         print(end - start)
#
#     return inner
#
#
# inner = outer(index)
# inner(aa=1)

# def aa(*args, **kwargs):
#     # print(args, kwargs)
#     print(*args, **kwargs)  # [1, 2, 3] {'user': 'jason', 'pwd': 123}
#  print 不了 **字典
#
# aa(x=1)
# print(x=1)   就会报错
# 形参 的 *  多余的位置参数以元组的形式接收给 * 后args
# 实参 的 * 就是for循环 一个个取出来 然后一次性的传给函数
# 形参 的 ** 会把多余的关键字参数 以键值对的形式 放在字典里
# 实参 的** 会把字典里的键值对写成 键=值的形式

# 需求当原函数有返回值的时候 怎么办


def index(aa, ):
    print("from index", aa)
    return "嘿嘿嘿"


def outer(xxx):
    def inner(*args, **kwargs):  # 他是怎么接的
        start = time.time()
        res =xxx(*args, **kwargs)  # 我就是怎么传的
        time.sleep(0.3)
        end = time.time()
        print(end - start)
        return res

    return inner


index = outer(index)
res = index(aa=1)
print(res)

# 只用那个值来接收原函数的返回值 然后在把它返回出来就行了

# 这样一个装饰器的就完成了 只是需要自己先写  inner = outer(index)

装饰器模板

def outer(func):
    def inner(*args, **kwargs):
        res = func(*args, **kwargs)
        return res
    return inner

装饰器语法糖

# 如果不想写那么 就需要语法糖

# 如果要想使用语法糖一定要把装饰器写到 被装饰函数的上面

# def outer(xxx):
#     def inner(*args, **kwargs):  # 他是怎么接的
#         start = time.time()
#         res =xxx(*args, **kwargs)  # 我就是怎么传的
#         time.sleep(0.3)
#         end = time.time()
#         print(end - start)
#         return res
#
#     return inner
#
#
# @ outer
# def index(aa, ):
#     print("from index", aa)
#     return "嘿嘿嘿"
#
#
# res = index(aa=1)
# print(res)

作业

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

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

path = os.path.dirname(__file__)
file_path = os.path.join(path, "db")
tag_dict = {"user": None}


def save(name, data):
    """保存"""
    if not os.path.exists(file_path):
        os.mkdir("db")
    with open(r"{}/{}.json".format(file_path, name), "w", encoding="utf8") as f:
        json.dump(data, f)
        return


def select(name):
    """查看"""
    if not os.path.exists(file_path):
        os.mkdir("db")
    name_list = os.listdir(file_path)
    # 如果文件不存在(用户没有注册)
    if "{}.json".format(name) not in name_list:
        # 则返回空
        return
    # 文件存在 则打开文件
    with open(r"{}/{}.json".format(file_path, name), "r", encoding="utf8") as f:
        data = json.load(f)
        return data


def outer(func):
    def inner(*args, **kwargs):
        if tag_dict["user"]:
            res = func(*args, **kwargs)
            return res
        else:
            print("您现在还没有权限, 请先登录")
            login()

    return inner


def register():
    """注册"""
    while True:
        data_dict = {}
        data_dict["name"] = input("请输入用户名:").strip()
        if data_dict["name"].lower() == "q":
            break
        res = select(data_dict["name"])
        if res:
            print("用户名已存在")
            continue
        data_dict["pwd"] = input("请输入密码:").strip()
        data_dict["quota"] = 15000
        save(data_dict["name"], data_dict)
        print("[{}]注册成功".format(data_dict["name"]))


def login():
    """登录"""
    while True:
        name = input("请输入用户名:").strip()
        if name.lower() == "q":
            break
        pwd = input("请输入人密码:").strip()
        data = select(name)
        if not data:
            print("用户不存在, 请先注册")
            continue
        if data["name"] == name and data["pwd"] == pwd:
            print("登陆成功!")
            tag_dict["user"] = name
            break
        else:
            print("用户名或密码错误")


@outer
def select_data():
    name = tag_dict["user"]
    data = select(name)
    if not data:
        print("用户不存在")
        return
    print(data)


@outer
def transfer():
    """转账"""
    while True:
        name = tag_dict["user"]
        t_name = input("请输入转账对象:").strip()
        if t_name.lower() == "q":
            break
        res = select(t_name)
        if not res:
            print("转账用户不存在!")
            continue
        # 获取想要转账的金额
        money = input("请输入转账金额:").strip()
        # 获取转账用户的数据
        data = select(name)
        # 获取转账用户的额度
        name_quota = data["quota"]
        # 转账用户的额度 减去 所转的金额
        new_money = name_quota - int(money)
        data["quota"] = new_money
        # 保存 用户的数据
        save(name, data)
        # 获取 被转账用户的数据
        t_data = select(t_name)
        # 获取 被转帐用户的金额
        t_quota = t_data["quota"]
        # 被转帐用户的金额加上转账金额
        new_t_money = t_quota + int(money)
        t_data["quota"] = new_t_money
        # 保存被转帐用户的数据
        save(t_name, t_data)
        print(f"""
        用户[{name}的剩余金额为[{new_money}]
        用户[{t_name}的剩余金额为[{new_t_money}]]
        """)


@outer
def withdraw():
    """提现"""
    while True:
        name = tag_dict["user"]
        money = input("请输入提现金额:").strip()
        if money.lower() == "q":
            break
        data = select(name)
        name_money = data["quota"]
        new_money = name_money - int(money)
        data["quota"] = new_money
        save(name, data)
        print("用户[{}]提现成功,剩余金额为[{}]".format(name, new_money))


choice_dict = {
    "1": register,
    "2": login,
    "3": select_data,
    "4": transfer,
    "5": withdraw,
    "6": exit,
}

while True:
    print("""
    1.注册
    2.登录
    3.查看
    4.转账
    5.提现
    6.退出
    """)
    choice = input("请输入功能编号:").strip()
    if not choice.isdigit():
        print("请输入数字")
        continue
    if choice not in choice_dict:
        print("输入的编号不存在")
        continue
    choice_dict.get(choice)()

    

posted @ 2022-10-11 19:05  可否  阅读(73)  评论(0)    收藏  举报