python高阶编程(九):装饰器

装饰器的作用:在不更改原功能函数内部代码,并且不改变调用方法的情况下为原代码添加新的
功能。

装饰器原理阐述:将被装饰的函数当做一个参数传到装饰器中,并且让被装饰的函数名指向装饰
器内部的函数,在装饰器的内部函数中用接收到的参数再调用被00装饰的函数

1、普通装饰器

import time
def count_time(func):
    def wrapper():
        strat_time = time.time() #获取开始时的时间
        func() #运行被装饰的函数
        end_time = time.time() # 获取结束时的时间
        t_time = end_time - strat_time #算出运行总时间
        print('运行总时间%:',t_time) #打印运行总时间
    return wrapper
@count_time
def work():
    time.sleep(2)
    print('原来函数的功能代码')
work()

2、装饰有参数和返回值函数

def count_time(func):
    def wrapper(a,b):
        strat_time = time.time()
        # 调用功能函数,接收功能函数返回的结果
        res = func(a,b)
        end_time = time.time()
        t_time = end_time - strat_time
        print('运行总时间%:',t_time)
        # 返回结果
        return res
    return wrapper b  

3、通用装饰器

def count_time(func):
    def wrapper(*args,**kwargs):
        strat_time = time.time()
        # 调用功能函数,接收功能函数返回的结果
        res = func(args,kwargs)
        end_time = time.time()
        t_time = end_time - strat_time
        print('运行总时间%:',t_time)
        # 返回结果
        return res
    return wrapper

4、装饰器装饰类

def decorator(cls):
    def wrapper(*args, **kwargs):
        print("----装饰器扩展代码1------")
        # 通过类实例化对象
        res = cls()
        print("----装饰器扩展代码2------")
        #使用类装饰器的时候,记得要返回被装饰的类调用的结果
        return res
    return wrapper
@decorator # MyClass =decorator(MyClass)
class MyClass:
pass

5、装饰器传参数

最外层参数,接收的是装饰器的参数
第二层参数,接收是被装饰的函数
第三层参数,接收的是被装饰函数的参数

def musen(name, age):
    def decoreter(func):
        def wrapper(*args, **kwargs):
            print("装饰器传递的参数name:", name)
            print("装饰器传递的参数age:", age)
            res=func(*args, **kwargs)
            return res
        return wrapper
    return decoreter

@musen('11', 18)  #
def work():
    print("----work----")

6、类实现装饰器

前面我们是用闭包函数来实现的装饰器,那么接下来给大家扩展一下,使用类来当做一个装饰器
来用
如果要把类当做一个装饰器来用,有两步操作,
首先在 init 方法中,把被装饰的函数赋值给一个实例属性,
然后再了类里面实现一个 call 方法,在call方法中调用原来的函数。

class Test(object):
    def __init__(self,func):
        self.func = func
    def __call__(self, *args, **kwargs):
        print('这个是类装饰器')
        self.func(*args,**kwargs)



class Decorator:
    def __init__(self, func):
        self.func = func

    def __call__(self, *args, **kwargs):
        print("装饰器扩展代码1111111111111")
        res = self.func()
        print("装饰器扩展代码2222222222")
        return res

# 通过类作为装饰器
@Decorator  # work = Decorator(work)
def work():
    print("----work----------")

work()
#结果
装饰器扩展代码1111111111111
----work----------
装饰器扩展代码2222222222

7、装饰器的副作用

问题:函数/类 在被装饰器装饰了之后,会改变原函数名的指向,无法再通过原函数名去获取函数
原有的属性,
消除装饰器的副作用:functools.wraps

def decorator(func):
    #@wraps(func)  # 消除装饰器的副作用
    def wrapper(*args, **kwargs):
        """装饰器内部wrapper的注释"""
        res = func(*args, **kwargs)
        return res
    return wrapper


@decorator
def work(a, b):
    """
    实现两个对象相加的方法
    :param a: 数字1
    :param b: 数字2
    :return: 两个数相加的结果
    """
    res = a + b
    print('a+b的结果为:', res)



# 获取函数的文档字符串
print("函数的文档字符串注释:", work.__doc__)
# 获取函数的name属性
print('函数名:', work.__name__)

#结果
不加@wraps(func)
函数的文档字符串注释: 装饰器内部wrapper的注释
函数名: wrapper

加@wraps(func)
函数的文档字符串注释: 
    实现两个对象相加的方法
    :param a: 数字1
    :param b: 数字2
    :return: 两个数相加的结果
    
函数名: work

8、通过装饰器修改属性

def mark(func):
    func.name = '002'
    return func
    
# 通过装饰器给原函数动态添加属性
@mark  # work = mark(work)
def work():
    print("----work----")

# work.name = '001'
# work()
print(work.name)#002
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值