【python基础】第18回 函数 装饰器

本章内容概要

1. 闭包函数简介

2. 闭包函数的实际应用

3. 装饰器简介

4. 装饰器推导流程(重要)

5. 装饰器功能完善

6. 装饰器统一使用模板(通用)

7. 装饰器语法糖

本章内容详解

1. 闭包函数简介

1.1 闭包函数

1. 定义在函数内部的函数

2. 内部函数使用了外部函数名称空间中的名字

函数被当做数据处理时,始终以自带的作用域为准。若内嵌函数包含对外部函数作用域(而非全局作用域)中变量的引用,那么该’内嵌函数’就是闭包函数,简称闭包(Closures)

复制代码
def func():
    username = 'jason'
    def index():
        print(username)

    return index
# 思考如何在全局调用index
res = func()
print(res)
res()
复制代码

2. 闭包函数的实际应用

2.1 给函数体代码传值的方式1:通过形参

def func(xxx):
    print(xxx)

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

复制代码
def index(username):
    # username = 'jason'
    def func():
        print(username)
    return func
res = index('jason')
res()
res1 = index('kevin')
res1()
复制代码

3. 装饰器简介

3.1 装饰器的本质

’装饰’代指为被装饰对象添加新的功能,’器’代指器具/工具,装饰器与被装饰的对象均可以是任意可调用对象。概括地讲,装饰器的作用就是在不修改被装饰对象源代码和调用方式的前提下为被装饰对象添加额外的功能。装饰器经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等应用场景,装饰器是解决这类问题的绝佳设计,有了装饰器,就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。

在不改变被修饰对象原来的'调用方式'和‘内部代码’的情况下给被装饰对象添加新功能

def func():
    print(123)
func()  # 每次执行之前需要校验用户身份

3.2 装饰器的原则

对修改封闭 对扩展开放

3.3 知识储备

1. 时间戳

import time

print(time.time())  # 1657012675.6190832
'''时间戳(秒数):当前距离1970年1月1日0时0分0秒所经历的秒数'''

 2. 统计代码的运行时间

复制代码
import time

print(time.time())  # 1657012675.6190832
'''时间戳(秒数):当前距离1970年1月1日0时0分0秒所经历的秒数'''
start_time = time.time()
for i in range(1000):
    print(i)
end_time = time.time()
print('for循环的执行时间是:%s'%(end_time - start_time))
复制代码

 3. 让程序原地等待三秒中

import time
start_time = time.time()
time.sleep(3)
end_time = time.time()
print('原地等待3秒执行时间是:%s'%(end_time - start_time))

4. 装饰器推导流程(重要)

4.1 统计index函数的执行时间

复制代码
import time


def index():
    time.sleep(3)
    print('from index')
'''统计index函数的执行时间'''
start_time = time.time()  # 在调用index函数之前获取一下时间戳
index()  # 调用index函数
end_time = time.time()
print(end_time - start_time)
复制代码

4.2  缺陷:如果有多个index需要统计时间 则需要重复编写代码 ,解决措施:封装成函数

复制代码
import time


def index():
    time.sleep(3)
    print('from index')
def get_time():
    start_time = time.time()  # 在调用index函数之前获取一下时间戳
    index()  # 调用index函数
    end_time = time.time()
    print('函数的执行时间是:',end_time - start_time)
get_time()


get_time()
复制代码

 4.3  缺陷:如果有多个不同的函数需要统计时间 那么上述的解决措施不够完善,解决措施:给函数体添加形参(动态传参)

复制代码
def home():
    time.sleep(5)
    print('from home')

def get_time(xxx):
    start_time = time.time()  # 在调用index函数之前获取一下时间戳
    xxx()  # 调用index函数
    end_time = time.time()
    print('函数的执行时间是:',end_time - start_time)
get_time(index)
get_time(home)
复制代码

 4.4 缺陷:不同形参个数的函数无法兼容统计 解决措施: *args **kwargs  但是在我们目前的代码中无法实现(暂且忽略)

5. 装饰器功能完善

5.1 缺陷:改变了原来的调用方式,解决措施:装饰器推导流程

1.第一种直接利用形参的形式传参无法实现不改变调用方式

# 1.第一种直接利用形参的形式传参无法实现不改变调用方式
def get_time(xxx):
    start_time = time.time()  # 在调用index函数之前获取一下时间戳
    xxx()  # 调用index函数
    end_time = time.time()
    print('函数的执行时间是:',end_time - start_time)

2.第二种方式尝试:闭包函数

复制代码
import time
def index():
    time.sleep(3)
    print('from index')


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


# 2.第二种方式尝试:闭包函数
def outer(xxx):
    # xxx = index
    def get_time():
        start_time = time.time()  # 在调用index函数之前获取一下时间戳
        xxx()  # 调用index函数
        end_time = time.time()
        print('函数的执行时间是:', end_time - start_time)

    return get_time

res = outer(index)
res()
res1 = outer(home)
res1()
复制代码

 

 

 5.2 装饰器各种版本 优化

复制代码
import time


"""针对有参无参函数如何兼容"""
def outer(xxx):
    def get_time(*args, **kwargs):
        start_time = time.time()  # 在调用index函数之前获取一下时间戳
        res = xxx(*args, **kwargs)  # 调用index函数
        end_time = time.time()
        print('函数的执行时间是:', end_time - start_time)
        return res
    return get_time

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

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

home = outer(home)
xxx = home()
print(xxx)


index = outer(index)
res = index('jason')
print(res)
复制代码

6. 装饰器统一使用模板(通用)

复制代码
from functools import wraps
def outer(func_name):
    @wraps(func_name)  # 仅仅是为了让装饰器不容易被别人发现 做到真正的以假乱真
    def inner(*args, **kwargs):
        print('执行被装饰对象之前可以做的额外操作')
        res = func_name(*args, **kwargs)
        print('执行被装饰对象之后可以做的额外操作')
        return res
    return inner
复制代码

7. 装饰器语法糖

help函数可用于查找模块,功能,类,关键字等的文档

复制代码
from functools import wraps
def outer(func_name):
    @wraps(func_name)  # 仅仅是为了让装饰器不容易被别人发现 做到真正的以假乱真
    def inner(*args, **kwargs):
        print('执行被装饰对象之前可以做的额外操作')
        res = func_name(*args, **kwargs)
        print('执行被装饰对象之后可以做的额外操作')
        return res
    return inner
import time

@outer  #  home = outer(真正的函数名home)
def home():
    '''我是home函数 我要热死了!!!'''
    time.sleep(1)
    print('from home')
    return 'home返回值'

help(home)
home()
复制代码

posted @   |相得益张|  阅读(33)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示