Python之装饰器(基础)

1.定义一个简单的装饰器

装饰器:
    把一个函数当作参数,返回一个替代版的函数
    本质上就是一个返回函数的函数

“在不改变原函数的基础上,给函数增加功能”

例1:在不更改函数fun1的前提下,在输出 hello python 之前先输出 *****************

# 1.定义装饰器
def decorator(fun):
    def prints():
        print('*****************')
        fun()
    return prints

# 2.添加装饰器
@decorator
def say_hello():
    print('hello python')

# 3.调用函数
say_hello()

在这里插入图片描述
2.调用函数的两种方式

例2:在不更改函数fun1的前提下,在输出This is a function之前先输出系统时间

# 导入时间模块
import time

# 定义装饰器(它的形参是一个函数)
def decorator(func):
    def wrapper():
        # 打印时间
        print(time.time())
        # 调用接收的函数
        func()
    # 必须返回wrapper函数,否则将无输出信息
    return wrapper

# 方式1:
def fun1():
    print('This is a function')

# 1.无需要更改函数,但需要更改调用方式
fun1 = decorator(fun1)
fun1()

在这里插入图片描述

# 导入时间模块
import time

# 定义装饰器(它的形参是一个函数)
def decorator(func):
    def wrapper():
        # 打印时间
        print(time.time())
        # 调用接收的函数
        func()
    # 必须返回wrapper函数,否则将无输出信息
    return wrapper

# 方式2:
@decorator
def fun1():
    print('This is a function')

# 无需要更改函数,也无需要更改调用方式
fun1()

在这里插入图片描述
3.定义一个有参数的函数

# 导入时间模块
import time

# 定义装饰器(它的形参是一个函数)
def decorator(func):
    # *args:可变参数(可以接收任意多个参数),因为fun1,fun2函数里有不同个数的参数;
    # **kwargs:关键字参数(用来接收字典),因为fun3函数里有关键字参数
    def wrapper(*args,**kwargs):
        # 打印时间
        print(time.time())
        # 调用接收的函数
        func(*args,**kwargs)
    # 必须返回wrapper函数,否则将无输出信息
    return wrapper

# (1) 定义有一个参数的函数

@decorator
def fun1(func_name):
    #  + 表示连接
    print('This is a function ' + func_name)

fun1('test')

# (2) 定义有两个参数的函数
@decorator
def fun2(func_name1,func_name2):
    print('This is a function ' + func_name1)
    print('This is a function ' + func_name2)

fun2('test1','test2')

# (3) 定义有关键字参数的函数
@decorator
# **kwargs:关键字参数,用来接收字典
def fun3(func_name1,func_name2,**kwargs):
    print('This is a function ' + func_name1)
    print('This is a function ' + func_name2)
    print(kwargs)

fun3('tes1','test2',a='1',b='2',c='westos')

在这里插入图片描述
4.装饰器实现一个函数计时器

解决:

问题1: 如何保留被装饰函数的函数名和帮助信息文档
            在装饰器中添加:  @functools.wraps(fun)

问题2: 如果被装饰函数有返回值,该如何定义装饰器
			res = fun(*args,**kwargs)
			return res
import time
import random
import string
import functools

# 使用序列生成式的方式:随机生成100个字母,将其定义为一个列表
li = [random.choice(string.ascii_letters) for i in range(100)]
# print(li)

# 定义装饰器,来比较这两种方式的运行效率
def timeit(fun):
    #  解决问题1:
    #  保留被装饰函数的函数名和帮助信息文档
    @functools.wraps(fun)
    # @1.一般都写上可变参数和关键字参数,
    # 无论需要装饰的函数是否有参数,有就使用,没有就不使用
    def wrapper(*args,**kwargs):
        """这是wrapper函数"""
        start_time = time.time()
        print(start_time)
        #1. fun(*args, **kwargs)
        # @2.一般都将其赋给变量,便于返回函数返回值,
        # 无论被装饰函数是否有return,有则使用,没有则不使用
        res = fun(*args,**kwargs)
        end_time = time.time()
        print(end_time)
        # 多保留几位小数,才能看到时间差
        print('运行时间为:%.6f' %(end_time - start_time))
        # 解决问题2:
        return res
    return wrapper

# 用逗号来连接列表中的所有元素并输出

# 方式1:(自定义方法)
@timeit
def con_add():
    """这是con_add函数"""
    s = ''
    for i in li:
        s += (i + ',')
    print(s)

con_add()


# 方式2:(系统内置方法:join方法)
@timeit
def join_add():
    """这是join方法"""
    print(','.join(li))

join_add()

## 发现内置函数比自定义函数运行效率要高

# # 如果装饰器内没有 @functools.wraps(fun), 则返回装饰函数的函数名和帮助信息文档
# # 如果装饰函数中也没有注释,则返回 None
# 
# # 1.查看被装饰函数的帮助文档
# print(con_add.__doc__)
# print(join_add.__doc__)
# 
# # 2.查看被装饰函数的函数名
# print(con_add.__name__)
# print(join_add.__name__)

在这里插入图片描述

import time
import random
import string
import functools

# 使用序列生成式的方式:随机生成100个字母,将其定义为一个列表
li = [random.choice(string.ascii_letters) for i in range(100)]
# print(li)

# 定义装饰器,来比较这两种方式的运行效率
def timeit(fun):
    #  解决问题1:
    #  保留被装饰函数的函数名和帮助信息文档
    @functools.wraps(fun)
    # @1.一般都写上可变参数和关键字参数,
    # 无论需要装饰的函数是否有参数,有就使用,没有就不使用
    def wrapper(*args,**kwargs):
        """这是wrapper函数"""
        start_time = time.time()
        print(start_time)
        #1. fun(*args, **kwargs)
        # @2.一般都将其赋给变量,便于返回函数返回值,
        # 无论被装饰函数是否有return,有则使用,没有则不使用
        res = fun(*args,**kwargs)
        end_time = time.time()
        print(end_time)
        # 多保留几位小数,才能看到时间差
        print('运行时间为:%.6f' %(end_time - start_time))
        # 解决问题2:
        return res
    return wrapper

## 定义一个有返回值的函数

# 方式1:(自定义方法)
@timeit
def fun_list(n):
    # 列表生成式,计算n以内的各个元素的平方并将其存入列表中
    return [i ** 2 for i in range(n)]

# 调用时需要print打印
print(fun_list(5))


# 方式2:(系统内置方法:map方法)
@timeit
# 定义一个有返回值的函数
def fun_map(n):
    # map方法,计算n以内的各个元素的平方并将其存入列表中(lambda为匿名函数)
    return list(map(lambda x:x * 2,range(n)))

# 调用时需要print打印
print(fun_map(5))


## 由于内置方法:map 里使用到了匿名函数:lambda 所以它的运行效率不如自定义方法快

在这里插入图片描述
5.定义含参装饰器

import functools

# 定义带有参数的装饰器
# 1.第一个函数用来接收参数
# *kinds和*args一样,都是指可变参数,真正起作用的是*,后边跟任何字符均可,一般用args
# 由于后边已经使用了args所以换了一个字符串表示
def required_types(*kinds):
    # 2.第二个函数用来接收函数
    def required_type(fun):
        @functools.wraps(fun)
        # 3.第三个函数用来实现功能
        def wrapper(*args,**kwargs):
            # 遍历参数
            for i in args:
                # 参数是否符合要求
                if not isinstance(i,kinds):
                    # raise TypeError('参数必须为%s' %kinds)
                    print('参数必须为',kinds)
                    break
            else:
                #  执行函数,并返回函数返回值
                res = fun(*args,**kwargs)
                return res
        return wrapper
    return required_type

## 添加装饰(带有参数)
# 只能是整型
# @required_types(int)
# 浮点型或者整型,无先后顺序之分
@required_types(float,int)
def add(a,b):
    return a + b

# print(add(1,3))
print(add('westos',3.0))

在这里插入图片描述
6.多个装饰器的执行

import functools

# 定义装饰器1
def decorator_a(fun):
    print('Get in decorator_a')
    @functools.wraps(fun)
    def inner_a(*args,**kwargs):
        print('Get in inner_a')
        # 调用函数
        res = fun(*args,**kwargs)
        return res
    return inner_a

# 定义装饰器2
def decorator_b(fun):
    print('Get in decorator_b')
    @functools.wraps(fun)
    def inner_b(*args,**kwargs):
        print('Get in inner_b')
        # 调用函数
        res = fun(*args,**kwargs)
        return res
    return inner_b

# 添加装饰
@decorator_b
@decorator_a

# 定义被装饰函数
def f(x):
    print('Get in f')
    return x ** 2

print(f(3))

# 外层:先执行装饰器decorator_a,再执行decorator_b(从下到上)
# 内层:先执行inner_b,再执行inner_a(先执行后返回的)
# 仅与添加装饰的顺序有关,与定义装饰器的顺序无关
# 外层函数从下到上依次执行,内层函数先执行后返回的

在这里插入图片描述

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值