函数装饰器

内容概要

  • global 与 nonlocal
  • 函数名的多种用法
  • 闭包函数
  • 装饰器简介
  • 装饰器的推导流程
  • 装饰器的模板
  • 装饰器的语法糖

内容详解

global 与 nonlocal

1.global:若要在函数内修改全局名称空间中名字的值,当值为不可类型时,就可以使用global关键字

global关键字:
# money = 100
# def index():
#     global money # 打破局部空间 直接修改全局名称空间中的数据
#     money = 300
#
#
# index()
# print(money)

当实参的值为可变类型时,函数体内对该值的修改将直接反应到原来的值

l1 = [1, 2, 3, 4, 5]
def num_list(nums):
    nums.append(6)

num_list(l1)
print(l1)
#结果为
[1, 2, 3, 4, 5, 6]

2.nonlocal:对于嵌套多层的函数,可以使用nonlocal关键字

2.nonlocal关键字:
# def index():
#     name = 'jason'
#     def inner():
#         nonlocal name # 打破内层局部空间 直接修改外部局部空间的数据
#         name ='kevin'
#     inner()
#     print(name)
# index()

函数名的多种用法

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

1.函数名可以当做变量名赋值

def index():  # 定一个index的函数
    print('可以赋值给res吗')
res = index   # 将函数index赋值给res 
res() # res也可以调用index函数内的功能

2.函数名可以当做函数的参数

def func():  # 定一个func的函数
    print('from func') 
def index(a):  # 把func做为实参传给a 函数func和a做临时绑定
    print(a)  # 打印a查看func函数的内存地址
    a() # a可以调用func的函数内的功能
index(func)

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

def index(): # 1.定义一个index的函数
    print('from index')
def func():  # 2.定义一个func的函数
    print('from func') 
    return index # 3.把index做为返回值,放回给func
res = func() #4.用res来接收func()的返回值 相当于把res = index
print(res) # 5.打印res来查看index的内存地址
res() #6.res()就可以调用index函数的功能

4.函数名可以当做容器类型的(可以存放多个数据的数据类型)的数据值

def regiser():
    print('注册功能')
def login():
    print('登录功能')
def withdraw():
    print('提取功能')
def transfer():
    print('转账功能')
def shopping():
    print('购物功能')
    
# 定义功能编号与功能的对应关系
func_dict = {
    '1':regiser,
    '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_dict.get(choice)
    else:
        print('该功能编号不存在')

闭包函数

1.定义:在函数内部的函数 并且用到了外部函数名称空间的名字

1.定义在函数内容
2.用到外部函数名称空间的名字

2.闭包函数实际应用>>>:是另一种给函数体代码传参的方式

2.1给函数体代码传参的方式1:代码里面缺什么变量名形参,里面就补什么变量名

def register(name, age):
    print(f"""
    姓名:{name}
    年龄:{age}

""")
register('jamer', 40)

2.2给函数体代码传参的方式2:闭包函数

def outer(name, age):
    def register():
        print(f"""
        姓名:{name}
        年龄:{age}
        
        """)
    return register
res = outer('jamer',18)
res()
res()
res()
res()
res = outer('curry', 45)

装饰器简历

1.概念

在不改变被装饰对象原代码和调用方式的情况下给被装饰对象添加新的功能

2.本质

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

3.口诀

对修改封闭 对扩展开放

4.储备知识

时间相关操作
import time
# print(time.time()) # 时间戳(距离1970-01-01 00:00:00所经历的秒数)
# time.sleep(3)
# print('hhhh')



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


装饰器推导流程

import time


def index():
    time.sleep(2)
    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)

'''2.index调用的地方较多 代码不可能反复拷贝>>>:相同的代码需要在不同的位置反复执行>>>:函数'''


def get_time():
    start_time = time.time()
    index()
    end_time = time.time()
    print('函数index的执行时间为>>>:', end_time - start_time)


get_time()
'''3.函数体代码写死了 只能统计index的执行时间 如何才能做到统计更多的函数运行时间 直接传参变化统计的函数'''


def get_time(xxx):
    start_time = time.time()
    xxx()
    end_time = time.time()
    print('函数index的执行时间为>>>:', end_time - start_time)


get_time(index)
get_time(home
'''4.虽然实现了一定的兼容性 但是并不符合装饰器的特征 第一种传参不写 只能考虑闭包'''


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

    return get_time


res = outer(index)
res()
res1 = outer(home)
res1()
'''5.调用方式还是不对 如何变形>>>:变量名赋值绑定(******)'''


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

    return get_time


index = outer(index)
index()
home = outer(home)
home()
'''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 func3')


func(123)


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

    return get_time


# 必须要没参数传值
func2 = outer(func2)
func2()
# 必须要有一个参数传值
func = outer(func)
func(1)
# 必须要有两个参数传值
func1 = outer(func1)
func1(1, 2)
'''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):
        start_time = time.time()
        xxx(*args, **kwargs)
        end_time = time.time()
        print('函数index的执行时间为>>>:', end_time - start_time)

    return get_time


func = outer(func)
func(123)
func1 = outer(func1)
func1(1, 2
'''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('函数index的执行时间为>>>:', end_time - start_time)
        return res

    return get_time


func = outer(func)
func(123)
func1 = outer(func1)
res = func1(123, 222)
print(res)

装饰器模板

1.def outer(func):
   2. def inner(*args, **kwargs):
        5.#执行被装饰对象之前可以做的额外操作
        6.res =3.func(*args, **kwargs)
        7# 执行被装饰对象之后可以做的额外操作
       8. return res
    4.return inner

装饰器语法糖

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("语法糖是给什么鬼")
    return "func"

@outer # index =outer(index)
def index():
    print("装饰器是个什么鬼")
    return "index"


func()
index()
posted @   hugmi男孩  阅读(29)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
  1. 1 原来你也在这里 周笔畅
  2. 2 世间美好与你环环相扣 柏松
  3. 3 起风了 吴青峰
  4. 4 极恶都市 夏日入侵企划
起风了 - 吴青峰
00:00 / 00:00
An audio error has occurred, player will skip forward in 2 seconds.

作词 : 米果

作曲 : 高橋優

编曲 : 刘胡轶/貢多杰

制作人 : 刘胡轶/吴青峰

配唱制作人 : 刘胡轶

乐器监制 : 刘胡轶

吉他 : 胡晨

贝斯 : 甯子达

弦乐录音棚 : 中国剧院录音棚

录音工程师 : 倪涵文/李游/李杨/邢铜/韩宽/李巍

录音监制 : 倪涵文/李游

混音&母带工作室 : OKmastering studio

混音&母带工程师 : 全相彦

制作协力 : 刘西洋

制作发行 : 智慧大狗 × 天才联盟

出品人 : 张葛

监制 : 崔恕/王明宇

弦乐监制 : 李朋

弦乐 : 国际首席爱乐乐团

鼓(打击乐):祁大为

和音编写&演唱:鱼椒盐

人声&吉他&鼓(打击乐)录音棚:55Tec studio

我曾将青春翻涌成她

我曾将青春翻涌成她

也曾指尖弹出盛夏

心之所动 且就随缘去吧

这一路上走走停停

这一路上走走停停

顺着少年漂流的痕迹

迈出车站的前一刻

竟有些犹豫

不禁笑这近乡情怯

不禁笑这近乡情怯

仍无可避免

而长野的天

依旧那么暖

风吹起了从前

从前初识这世间

从前初识这世间

万般流连

看着天边似在眼前

也甘愿赴汤蹈火去走它一遍

如今走过这世间

如今走过这世间

万般流连

翻过岁月不同侧脸

措不及防闯入你的笑颜

我曾难自拔于世界之大

我曾难自拔于世界之大

也沉溺于其中梦话

不得真假 不做挣扎 不惧笑话

我曾将青春翻涌成她

我曾将青春翻涌成她

也曾指尖弹出盛夏

心之所动 且就随缘去吧

逆着光行走 任风吹雨打

短短的路走走停停

短短的路走走停停

也有了几分的距离

不知抚摸的是故事 还是段心情

也许期待的不过是 与时间为敌

再次看到你

微凉晨光里

笑得很甜蜜

从前初识这世间

从前初识这世间

万般流连

看着天边似在眼前

也甘愿赴汤蹈火去走它一遍

如今走过这世间

如今走过这世间

万般流连

翻过岁月不同侧脸

措不及防闯入你的笑颜

我曾难自拔于世界之大

我曾难自拔于世界之大

也沉溺于其中梦话

不得真假 不做挣扎 不惧笑话

我曾将青春翻涌成她

我曾将青春翻涌成她

也曾指尖弹出盛夏

心之所动 且就随缘去吧

晚风吹起你鬓间的白发

晚风吹起你鬓间的白发

抚平回忆留下的疤

你的眼中 明暗交杂 一笑生花

我仍感叹于世界之大

我仍感叹于世界之大

也沉醉于儿时情话

不剩真假 不做挣扎 无谓笑话

我终将青春还给了她

连同指尖弹出的盛夏

心之所动 就随风去了

以爱之名 你还愿意吗

点击右上角即可分享
微信分享提示