函数名的多种用法及装饰器

global与nonlocal

money = 666
def index():
    global money
    money = 123
index()
print(money)  # 123
"""
局部名称空间直接修改全局名称空间中的数据
"""

image

def index():
    name = 'jason'
    def inner():
        nonlocal name
        name = 'kevin'
    inner()
    print(name)
index()  # kevin
"""
内部局部名称空间修改外层局部名称空间中的数据
"""

image

函数名的多种用法

+++++++++++
函数名其实绑定的也是一块内存地址 只不过该地址里面存放是不是数据值而是一段代码 函数名加括号就会找到该代码并执行
+++++++++++

1. 可以当做变量名赋值
  def index():pass
  res = index
  res

image

2. 可以当做函数的参数
def index():
    print('from index')
def func(a):
    print(a)  # 打印了a变量名绑定的数据值index函数的内存地址
    a()  #类似于执行了index()函数
func(index)

image

3. 可以当做函数的返回值

def index():
    print('from index')

def func():
    print('from func')
    return index

res = func()  # from func
print(res)   #打印index函数内存地址
res()   # 相当于执行index()函数的代码块 from index


def index():
    print('from index')
    def func():
        print('from func')
    return func
res = index()  # from index
print(res)  # 打印func函数的绑定内存地址
res()   # 相当于执行func()函数的代码块 from func

image

image

4. 可以当做容器类型(可以存放多个数据的数据类型)的数据
def register():
    print('注册功能')

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

def withdraw():
    print('提现功能')

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

def shopping():
    print('购物功能')

# 定义功能编号与功能的对应关系
func_dict = {
    '1': register,
    '2': login,
    '3': withdraw,
    '4': transfer,
    '5': shopping
}
while True:
    print("""
    1.注册功能
    2.登录功能
    3.提现功能
    4.转账功能
    5.购物功能
    """)
    choice = input('>>>:').strip()
    if choice in func_dict:
        func_name = func_dict.get(choice)
        func_name()
    else:
        print('功能编号不存在')

闭包函数

"""
定义在函数内部的函数 并且用到了外部函数名称空间中的名字
  1. 定义在函数内
  2. 用到外部函数名称空间中的名字
"""
# 简单版闭包函数
def index():
    name = 'jason'
    def inner():
        print(name)

# 给函数体代码传参的方式1: 代码里面缺什么变量名形参里面就补什么变量名
def register(name,age):
    print(f"""
    姓名:{name}
    年龄:{age}
    """)
register('jason', 18)

# 给函数体代码传参的方式2:闭包函数
def outer(name, age):
    def register():
        print(f"""
        姓名:{name}
        年龄:{age}
        """)

    return register


res = outer('jason', 18)
res()
res()

image

image

装饰器简介

1.概念
  在不改变被装饰对象原代码和调用方式的情况下给被装饰对象添加新的功能
2.本质
  并不是一门新的技术,而是由函数参数、名称空间、函数名多种用法、闭包函数组合到一起的结果
3.口诀
对修改封闭 对扩展开放
4.储备知识
时间相关操作
import time
print(time.time())  #时间戳(距离1970-01-01 00:00:00所经历的秒数)
time.sleep(3)
print('睡醒了 干饭')

count = 0
#循环之前先获取时间戳
start_time = time.time()
while count < 1000:
    print('呵呵')
    count += 1
end_time = time.time()
print('循环消耗的时间:', end_time - start_time)

装饰器推导流程

import  time
def index():
    time.sleep(3)
    print('from index')
def home():
    time.sleep(1)
    print('from home')
    
'''1.直接在调用index函数的前后添加代码'''
start_time = time.time()
index()
end_time = time.time()
print('函数index的执行时间为>>>', end_time - start_time)

image

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

'''2.index调用的地方较多 代码不可能反复拷贝>>>:相同的代码需要在不同的位置反复执行>>>:函数'''
def get_time():
    start_time = time.time()
    index()
    end_time = time.time()
    print('函数index的执行时间为>>>', end_time-start_time)
get_time()

image

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

'''3.函数体代码写死了 只能统计index的执行时间 如何才能做到统计更多的函数运行时间 直接传参变换统计的函数'''
def get_time(xxx):   #xxx为形参,接收函数名get_time实参传进来的函数
    start_time = time.time()
    xxx()  # 接收index函数名并执行index()函数体内的代码
    end_time = time.time()
    print('函数的执行时间为>>>', end_time - start_time)
get_time(index) # 接收index函数名并执行get_time函数体内代码
get_time(home)  # 接收home函数名并执行get_time函数体内代码

image

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

'''4.虽然实现了一定的兼容性 但是并不符合装饰器的特征 第一种传参不写 只能考虑闭包'''
def outer(xxx):
    # xxx = index
    def get_time():
        start_time = time.time()
        xxx()
        end_time = time.time()
        print('函数的执行时间为>>>', end_time - start_time)
    return get_time
res = outer(index)
res()
res1 = outer(home)
res1()

image

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

'''5.调用方式还是不对 如何变形>>>:变量名赋值绑定(******)'''
def outer(xxx):
    def get_time():
        start_time = time.time()
        xxx()
        end_time = time.time()
        print('函数的执行时间为>>>', end_time - start_time)
    return get_time
# res = outer(index)  #赋值符号的左边是一个变量名 可以随意包括命名
# res()
# res1 = outer(home)
# res1()
index = outer(index)
index()
home=outer(home)
home()

image

import time
'''6.上述装饰器只能装饰无参函数 兼容性太差'''
def func(a):
    time.sleep(0.1)
    print('from func', a)

def func1(a,b):
    time.sleep(0.2)
    print('from func1', a, b)

def func2():
    time.sleep(0.3)
    print('from func2')

def outer(xxx):
    def get_time(a, b):
        start_time = time.time()
        xxx(a, b)
        end_time =time.time()
        print('函数的执行时间为>>>:',end_time - start_time)
    return get_time
func1 = outer(func1)
func1(1, 2)

image

import time
'''7.被装饰的函数不知道有没有参数及有几个参数 如何兼容'''
def func(a):
    time.sleep(0.1)
    print('from func', a)

def func1(a,b):
    time.sleep(0.2)
    print('from func1', a, b)

def outer(xxx):
    def get_time(*args, **kwargs):  # get_time(1,2,3)  args=(1,2,3)
        start_time = time.time()
        xxx(*args, **kwargs)   # xxx(*(1,2,3))   xxx(1,2,3)
        end_time =time.time()
        print('函数的执行时间为>>>:',end_time - start_time)
    return get_time
func = outer(func)
func(123)
func1=outer(func1)
func1(1,2)

image

import time
'''8. 如果被装饰的函数有返回值'''
def func(a):
    time.sleep(0.1)
    print('from func', a)
    return 'func'

def func1(a,b):
    time.sleep(0.2)
    print('from func1', a, b)
    return 'func1'

def outer(xxx):
    def get_time(*args, **kwargs):  # 接收形参
        start_time = time.time()
        res = xxx(*args, **kwargs)  #接收实参
        end_time =time.time()
        print('函数的执行时间为>>>:',end_time - start_time)
        return res
    return get_time
# func = outer(func)
# res = func(123)
# print(res)

func1 = outer(func1)  # 接收func1函数名,并进入到outer函数体内执行代码,并把return 的get_time函数返回并赋值给func1变量名,func1相当于就是get_time函数名。
res = func1(123, 123) # func1(即get_time函数)接收两个实参123,123并把实参带进get_time函数内,从上往下执行,
# 遇到xxx即就是第一行func1函数并去func1执行函数并把123,123带进func1函数体内,最后返回func1返回值,res就接收到func1返回值(func1),最后返回res(func1返回值)返回值。
print(res)  # 打印res返回值,即func1的返回值

image
参考小胖:
image

装饰器模板

# 务必掌握
def outer(func):
    def innter(*args, **kwargs):
        # 执行被装饰器对象之前可以做的额外操作
        res = func(*args, **kwargs)
        # 执行被装饰器对象之后可以做的额外操作
        return res
    return innter

装饰器语法糖

def outer(func_name):
    def inner(*args, **kwargs):
        print('执行被装饰对象之前可以做的额外操作')
        res = func_name(*args, **kwargs)
        print('执行被装饰对象之后可以做的额外操作')
        return res
    return inner
"""
语法糖会自动将下面挨着的函数名当做第一个参数自动传给@函数调用
"""

@outer  # func = outer(func)
def func():
    print('from func')
    return 'func'

@outer  # index = outer(index)
def index():
    print('from index')
    return 'index'

func()
index()

image

作业

# 编写一个用户认证装饰器
#   函数:register login transfer withdraw 
#   基本要求
#    执行每个函数的时候必须先校验身份 eg: jason 123
def outer(func):
    def inner(*args, **kwargs):
        username = input('请输入用户名>>>').strip()
        password = input('请输入登录密码>>>').strip()
        if username == 'jason' and password == '123':
            print(f'用户名验证通过')
            res = func(*args, **kwargs)
            return res
        else:
            print('用户名或密码错误')
    return inner

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

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

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




auth_dict = {
    '1': register,
    '2': login,
    '3': transfer,
    '4': withdraw
}

while True:
    print(f"""
    1.注册功能
    2.登录功能
    3.转账功能
    4.提现功能
    """)
    choice = input('请输入功能编号>>>:').strip()
    if choice in auth_dict:
        auth_dict.get(choice)()
    else:
        print('请输入正确功能编号')

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

def outer(func):
    def inner(*args, **kwargs):
            # 声明is_check 为全局变量
            global is_check
            # 检测登录状态,如果为真,不用验证,直接登录
            if is_check:  
                res = func(*args, **kwargs)
                return res
            # 如果检测失败,需要进行用户名和密码登录验证,默认是False,即要登录验证,验证通过后变更is_check值
            else:
                username = input('请输入用户名>>>').strip()
                password = input('请输入登录密码>>>').strip()
                if username == 'jason' and password == '123':
                    is_check = True
                    res = func(*args, **kwargs)
                    return res

    return inner

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

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

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




auth_dict = {
    '1': register,
    '2': login,
    '3': transfer,
    '4': withdraw
}

while True:
    print(f"""
    1.注册功能
    2.登录功能
    3.转账功能
    4.提现功能
    """)
    choice = input('请输入功能编号>>>:').strip()
    if choice in auth_dict:
        auth_dict.get(choice)()
    else:
        print('请输入正确功能编号')

posted @   悠悠-winter  阅读(104)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
点击右上角即可分享
微信分享提示