python装饰器

1.装饰器工作原理:装饰器本身是一个函数,它参数是一个函数,
2.在装饰器内定义一个新函数,而新的函数又调用传进来的函数(定义一个嵌套函数,调用原函数)
3.最后返回这个新的函数(嵌套函数)
4.通过语法糖,将原函数名指向返回新的函数,实现未修改原码,从而添加功能

例一:原理如下
def func3():
    print('Have a nice day!')

# 定义装饰器
def outer(a):
    def inner():
        a()
        print('~~~~~~~~~~~~')

    return inner

# func3 = outer(func3)
func3()

例二:python中正确的书写语法,以及可以添加判断语句
# 定义装饰器
def outer(fun):
    def new_la(age):
        if age < 0:
            age = 0
        fun(age)

    return new_la

# 装饰器在装饰时,需要在每个函数前面加上,显然有些麻烦,Python提供了一种语法糖,即通过以下方式等通于例一中的
@outer
def la(age):
    print('age is %d' % age)

la(-10)

例三

"""
装饰器实现一个函数计时器
"""
import time
import random
import string
import functools

li = [random.choice(string.ascii_letters) for i in range(100)]


# 问题1:被装饰的函数有返回值
# 问题2:如何保留被装饰函数的函数名和帮助信息文档
def timeit(fun):
    """这是一个装饰器timeit"""

    # @functools.wraps(fun) #保留原函数注释和函数名
    def wrapper(*args, **kwargs):  # 接收可变参数和关键字参数
        """这是一个wrapper函数"""
        # args:元组 kwargs:字典
        # 在函数执行之前
        start_time = time.time()
        # 执行函数
        res = fun(*args, **kwargs)
        # 在函数执行之后
        end_time = time.time()
        print('运行时间为:%.6f' % (end_time - start_time))
        return res

    return wrapper

@timeit
def fun_list(n):
    """这是fun_list函数,被timeit装饰"""
    return [2 * i for i in range(n)]


@timeit
def fun_map(n):
    """这是fun_map函数,被timeit装饰"""
    return list(map(lambda x: x * 2, range(n)))


print(fun_list(50000))
print(fun_map(50000))
#通过timeit修饰器我们可以打印出原函数运行时间,发现内置函数+匿名函数实现功能的运行时间比我们通过循环所需时间要少



def fun(): 
    """这是fun函数""" 
    print('hello')

print(fun_list.__doc__)
print(fun_list.__name__)

# 本来函数名称与注释,应该是经过修饰器返回的新函数,但是我们在修饰器中加入@functools.wraps(fun)内置修饰器保留原来的名称与注释

# 添加前的结果

# 添加后的结果

 

例四

"""
 # 创建装饰器, 要求如下:
# 1. 创建add_log装饰器, 被装饰的函数打印日志信息;
# 2. 日志格式为: [字符串时间] 函数名: xxx, 运行时间:xxx, 运行返回值结果:xxx
"""
import functools
import time


def add_log(fun):
    @functools.wraps(fun)
    def wrapper(*args, **kwargs):
        start_time = time.time()
        res = fun(*args, **kwargs)
        end_time = time.time()
        print('[%s] 函数名:%s,运行时间:%.6f,运行返回值结果:%d' % (time.ctime(),fun.__name__, end_time - start_time, res))
        return res

    return wrapper


@add_log # 语法糖
def add(x, y):
    time.sleep(1) # 睡眠1s
    return x + y


add(1, 10)

 

"""
编写一个required_ints,条件如下:
    1.确保函数接收的每一个参数都是整形;
    2.如果参数不是正int,打印提示报错
    3.给装饰器添加参数
"""
import functools

def required_ints(fun):
    @functools.wraps(fun)
    def wrapper(*args, **kwargs):
        opt = True
        for i in args:
            if not isinstance(i, int): # 内置函数用户判断变量i类型是否为int
                print('ErrorType:', i, '参数必须是整形')
                opt = False
        else:
            if opt == True:
                return fun(*args, **kwargs)
     return wrapper


@required_ints
def lala(*args):
    print(args)
lala(1,2.2,3)
lala(1, 2, 3)

 

例五

#带参数的修饰器,在前面例四的基础上加入如下代码

import functools


def required_types(*types): # 在原来修饰器外嵌套一个新的函数用来接受参数
    def required_ints(fun):
        @functools.wraps(fun)
        def wrapper(*args, **kwargs):
            opt = True
            for i in args:
                if not isinstance(i, types): # 修改int为types我们就可以对比多个类型
                    print('ErrorType:', i, '参数必须是整形')
                    opt = False
            else:
                if opt == True:
                    return fun(*args, **kwargs)

        return wrapper

    return required_ints


# @required_ints
@required_types(int, float) # 新的修饰器加入参数
def lala(*args):
    print(args)


lala(1, 2, 3, 2.2)

#当调用添加float值是,就不会报错

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值