首页 > 其他分享 >装饰器

装饰器

时间:2022-10-11 20:36:03浏览次数:40  
标签:index 函数 func time print 装饰 def

1.global与nonlocal

1.global:局部名称空间修改全局名称空间的数据

n = 100
def index():
    global n
    n = 999

index()
print(n)  # 999 

2.nonlocal:内层局部名称空间修改外层局部名称空间中的数据
    
def index():
    n = 100
    def func():
        nonlocal n
        n = 500
    func()
    print(n)
index()   

2.函数名的多种用法

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

1.函数名可以当作变量名赋值
def index():
    print('from index')
res = index
res()  # from index

2.可以当做函数的参数
def index():
    print('from index')
def func(a):
    print(a)
    a()
func(index)  # <function index at 0x00000128C6607B80> from index

3.可以当做函数的返回值
def index():
    print('from index')
def func():
    print('from func')
    return index
res = func()
print(res)
res()  # from func <function index at 0x000001EC90A17B80> from index

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:
    choice = input('请输入您的任务编号>>>:').strip()
    if choice in func_dict:
        func_name = func_dict.get(choice)
        func_name()
    else:
        print('请输入正确任务编号')
"""
函数名(不加括号)可以放在字典的值中,调用时加括号
"""

3.闭包函数

1.定义在函数内部的函数,并且用到了外部函数名称空间的名字
"""
注意:
1.定义在函数内的函数
2.用到了外部函数名称空间中的名字
"""
def index():
    name = 'max'
    def func():
        print(f'{name}先生你好')
    func()
index()  # max先生你好
"""
由此可以得出结论:给函数传参的方式除了实参赋值,还有闭包函数。
"""
方式1:实参赋值
def index(name, age):
    print(f'{name}先生今年{age}岁了')
index('max', 25)  # max先生今年25岁了

方式2:闭包函数
def outer(name, age):
    def register():
        print(f"""
        姓名:{name}
        年龄:{age}
        """)
    return register
res = outer('jason', 18)
res()

res()  # 每执行一遍res都会打印一遍jason的信息

res = outer('max', 25)
res()  # 如果想重新传值则重新打印这两行代码

4.装饰器简介

1.概念:在不改变被装饰对象原代码和调用方式的情况下给被装饰对象添加新的功能。
    
2.本质:并不是一门新的技术,而是由函数参数、名称空间、函数名多种用法、闭包函数组合到一起的结果。
    
3.口诀:对修改封闭,对扩展开放。
    
4.储备知识:事件相关操作
	4.1时间戳:从1070年1月1日00:00到代码执行所经历的时间。
import time
print(time.time())  # 1665473850.1894429

	4.2等待若干秒之后在执行代码:
import time

time.sleep(3)
print('hello world')

	4.3统计函数执行的时间
import time
count = 1
start_time = time.time()
while count < 100:
    print('hello world')
    count += 1
end_time = time.time()
print('函数执行的时间:', end_time - start_time)  # 函数执行的时间: 0.001004934310913086

5.装饰器的推导流程

1.直接在函数调用的前后添加代码:
import time

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

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

start_time = time.time()
index()
end_time = time.time()
print('函数执行的时间:', end_time - start_time)  # from index 函数执行的时间: 3.0092296600341797

2.index调用的地方较多,代码不可能反复拷贝,相同的代码在不同的地方反复执行,使用函数更为便捷,定义一个get_time()函数
def get_time():
    start_time = time.time()
    index()
    end_time = time.time()
    print('函数执行的时间:', end_time - start_time)
get_time()  # from index 函数执行的时间: 3.007826566696167

3.如果这么写那么函数只能统计index()函数的运行时间,如何才能做到统计更多函数运行时间?直接传参
import time

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

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

def get_time(xxx):
    start_time = time.time()
    xxx()
    end_time = time.time()
    print('函数执行的时间:', end_time - start_time)
get_time(index)  # from index 函数执行的时间: 3.0078186988830566
get_time(home) # 函数执行的时间: 1.0134220123291016

4.上述代码调用函数只能把函数名传递到其它函数名中当做参数,不方便,闭包函数在这里更适用:
import time


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


def home():
    time.sleep(1)
    print('from home')
    
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()  # from index 函数体代码执行的时间为: 3.003218412399292
# res = outer(home)  # from home
# res()  # 函数体代码执行的时间为: 1.0004723072052002

5.上述结构函数调用时依然要被当做一个参数将函数名传递给其他函数,依然不符合调用函数的目标。
import time


def outer(xxx):
    def get_time():
        start_time = time.time()
        xxx()
        end_time = time.time()
        print('函数体代码执行的时间为:', end_time - start_time)

    return get_time


index = outer(index)  # res是函数名,可以任意起,当然也可以起index,但是左边的变量名index指向的不是函数体代码了
print(index)  # <function outer.<locals>.get_time at 0x000001A2F2566310> 此时的index指向的是get_time,现在xxx指向的是原来的index代码
index()  # from index 函数体代码执行的时间为: 3.014845371246338

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(3)
    print('from funcx')

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)
7.内层函数的参数个数要和被装饰的函数个数保持一致,被装饰得函数不知道参数个数,无法兼容
import time

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函数名返回给func时,222会被传给args变成一个元祖
        start_time = time.time()
        xxx(*args, **kwargs)  # 把元组打散成位置参数,传入get_time(func)函数体代码中
        end_time = time.time()
        print('函数体代码执行的时间为:', end_time - start_time)
    return get_time
func = outer(func)
func(222)

8.如果被装饰的函数有返回值,如何返回?
import time

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)  # 由于此时的func1已经指的是get_time了,所以get_time需要加一个返回值,会返回None,res是把真正的函数名加括号,得到返回值,然后作为get_time的返回值。
        end_time = time.time()
        print('函数体代码执行的时间为:', end_time - start_time)
        return res
    return get_time
func1 = outer(func1)
res = func1(1, 2)
print(res)

6.装饰器模板

1.模板:
def outer(func):
    def inner(*args, **kwargs):
        # 执行被装饰对象之前可以做的额外操作
        res = func(*args, **kwargs)  # 用来接收func的返回值
        # 执行被装饰对象之后可以做的额外操作 ,可有可无
        return res #把原func函数的返回值返回给inner()
    return inner  # 把局部名称空间中的inner返回出去,外面才可以用

2.模板套用:
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 func2(a, b ,c):
    time.sleep(0.2)
    print('from func2', a, b, c)
    return 'func2'

def outer(func1):
    def inner(*args, **kwargs):
        print('代码执行前的操作')
        res = func1(*args, **kwargs)
        print('代码执行后的操作')
        return res
    return inner
func1 = outer(func1)
res = func1(1, 2)  # 代码执行前的操作 from func1 1 2 代码执行后的操作
print(res)  # func1  

3.添加身份校验信息:
def func2(a, b ,c):
    time.sleep(0.2)
    print('from func2', a, b, c)
    return 'func2'

def outer(func2):
    def inner(*args, **kwargs):
        user_name = input('请输入您的用户名>>>:')
        user_pwd = input('请输入您的密码>>>:')
        if user_name == 'max' and user_pwd == '123':
            res = func2(*args, **kwargs)
            print('后')
            return res
        else:
            print('用户名或密码错误')
    return inner
func2 = outer(func2)
res = func2(1, 2, 3)
print(res)
"""
如果想要被装饰的函数执行并且有返回值,那么被装饰的函数和普通函数一样都要有函数名加括号、并且赋值给一个变量名,打印。
"""

7.装饰器语法糖

语法糖会自动将下面紧挨着的函数名当做第一个参数自动传给@函数点用
def outer(func):
    def inner(*args, **kwargs):
        print('代码执行前的操作')
        res = func(*args, **kwargs)
        print('代码执行后的操作')
        return res
    return inner

@outer
def index():
    print('我是index的函数体代码')
    return '我是index的返回值'
res = index()  # 代码执行前的操作 我是index的函数体代码 代码执行后的操作
print(res)  # 我是index的返回值

标签:index,函数,func,time,print,装饰,def
From: https://www.cnblogs.com/zkz0206/p/16782439.html

相关文章

  • python重点之装饰器
    global与nonlocal函数名的多种用法闭包函数装饰器简介无参装饰器有参装饰器装饰器模板装饰器语法糖今日详细内容global与nonlocalmoney=666defind......
  • 装饰器、global与nonlocal
    目录global与nonlocal函数名的多种用法闭包函数装饰器简介装饰器推导流程装饰器模版装饰器语法糖作业global与nonlocalglobalmoney=666defindex():globalmone......
  • python进阶之路11 闭包函数 装饰器
    函数名的多种用法函数名其实绑定的也是一块内存地址只不过该地址里面存放的不是数据值而是一段代码函数名加括号就会找到该代码并执行1.可以当作变量名赋值defindex......
  • 函数名的用法,闭包函数与装饰器
    函数的多种用法与装饰器global与nonlocal1.global用在局部名称空间直接修改全局名称空间中的数据x=111deffunc():globalx#修改全局名称空间x值x=2......
  • 装饰器+闭包掌握(python一大重要功能)
    目录global与nonlocal函数名的多种用法闭包函数装饰器简介1.概念2.本质3.口诀4.超前知识time模块装饰器推导装饰器模板装饰器语法糖作业global与nonlocalglobal#提升......
  • Java设计模式之 装饰模式实验报告书
    Java设计模式之装饰模式实验报告书姓名:班级:学号:实验三:装饰模式的应用一、实验目的熟练使用JAVA实现装饰模式,理解设计模式的模式动机,掌握模式结构,学习如何使用代码实现......
  • 函数装饰器
    global与nonlocalmoney=666defindex():globalmoneymoney=123index()print(money)"""局部名称空间直接修改全局名称空间中的数据"""defindex(......
  • 函数名的多种用法及装饰器
    目录global与nonlocal函数名的多种用法闭包函数装饰器简介装饰器推导流程装饰器模板装饰器语法糖作业global与nonlocalmoney=666defindex():globalmoneym......
  • 装饰器
    目录前言函数名的多种用法闭包函数补充time模块时间戳装饰器概念装饰器模板使用装饰器模板装饰器推导过程前言函数名的多种用法#1.函数名是名字defindex():p......
  • Python中的装饰器
     0前言千言万语抵不过一句话:“Matlab中可以使用Python.”今天修改代码过程中遇到装饰器语法,顺便总结一下以方便以后查看,也分享给大家,希望有帮助吧。装饰器(Decorato......