装饰器

参考:https://www.cnblogs.com/chenhuabin/p/11369359.html#_label1_0

一、定义

1.1 函数的四个特性

  • 可以赋值给其他变量
  • 可以作为参数传递给其他函数
  • 可以在内部定义一个函数
  • 可以当做返回值返回

装饰器的本质是函数,主要用来装饰其他函数,也就是为其他函数添加附加功能。

1.2 不用装饰器实现功能

def out_func(f):
    def inner_func():
        print('{}函数开始运行……'.format(f.__name__))
        f()
        print('{}函数结束运行……'.format(f.__name__))
    return inner_func


def func():
    print('正在完成功能')


if __name__ == '__main__':
    ceshi = out_func(func)
    ceshi()

  

1.3 使用装饰器实现功能

def out_func(f):
    def inner_func():
        print('{}函数开始运行……'.format(f.__name__))
        f()
        print('{}函数结束运行……'.format(f.__name__))
    return inner_func

@out_func
def func():
    print('正在完成功能')

if __name__ == '__main__':
    func()

1.4 结论

加了out_func装饰器的func 等价于 out_func(func)

二、装饰器的优点

2.1 装饰器不能修改被装饰的函数的源代码,也就是可以在不对被装饰函数做任何修改的前提下,给被装饰函数附加上一些功能。

使用@out_func对func函数进行装饰时,我们没有对func函数的代码做什么的改变,但是被装饰后的func函数却多了开始运行和结束运行的功能。

2.2,装饰器不能修改被装饰的函数的调用方式。在被装饰前,我们通过func调用这个函数,被装饰后,还是通过func调用这个函数。

2.3 代码更加精简。在上面代码中,我们只是用@out_func装饰了func一个函数,但是如果有多个函数需要添加开始运行和结束运行的提示功能,如果不用装饰器,那么就需要对每一个函数进行修改,则工作量和需要修改的代码量……

用了装饰器之后,只需要在需要添加这一功能的函数前面添加@func就可以了。

总之:一言以盖之,装饰器可以在不改变原函数调用方式和代码情况下,为函数添加一些功能,使代码更加精简。

我们使用装饰器来实现统计一个函数的运行时间的功能

import time
def timmer(f):
    def inner_func():
        start_time = time.time()
        f()
        end_time = time.time()
        print('{}函数运行消耗时间为:{}'.format(f.__name__, end_time-start_time))
    return inner_func

@timmer
def func():
    print('do_something函数运行……')
    time.sleep(1)


if __name__ == '__main__':
    func()

三、深入理解装饰器

3.1 被修饰的函数带返回值

def out_func(f):
    def inner_func():
        print('{}函数开始运行……'.format(f.__name__))
        ret = f()
        print('{}函数结束运行……'.format(f.__name__))
        return ret  # 这里返回值
    return inner_func

@out_func
def dec_dunc():
    print('正在完成功能')
    return '我是返回值'


if __name__ == '__main__':
    ret = dec_dunc()
    print(ret)

3.2 被装饰函数带参数

def out_func(f):
    def inner_func(name):
        print('{}函数开始运行……'.format(f.__name__))
        ret = f(name)
        print('{}函数结束运行……'.format(f.__name__))
        return ret
    return inner_func


@out_func
def func(name):
    print('你好,{}!'.format(name))
    return '我是返回值'


if __name__ == '__main__':
    ret = func('世界')
    print(ret)

 如果无法理解就理解成out_func(func)。

3.3 装饰器函数带参数

def key_language(key='python'):
    def out_func(f):
        def inner_func(name):
            if key == 'python':
                print('{}函数开始运行……'.format(f.__name__))
            else:
                print("关键字出错")
            ret = f(name)
            if key == 'python':
                print('{}函数结束运行……'.format(f.__name__))
            else:
                print("关键字出错")
            return ret
        return inner_func
    return out_func


@key_language('python')
def func(name):
    print('你好,{}!'.format(name))
    return '我是返回值'


if __name__ == '__main__':
    ret = func('世界')
    print(ret)

3.3 多层装饰器

import time


def timmer(f):
    def inner_func():
        print("timer开始运行")
        start_time = time.time()
        f()
        end_time = time.time()
        print('{}函数运行消耗时间为:{}'.format(f.__name__, end_time-start_time))
    return inner_func


def out_func(f):
    def inner_func():
        print('{}函数开始运行……'.format(f.__name__))
        ret = f()
        print('{}函数结束运行……'.format(f.__name__))
    return inner_func


@out_func
@timmer
def func():
    print("我是被装饰函数")
    time.sleep(1)


if __name__ == '__main__':
    func()

 注意运行顺序,下面的装饰器优先于上面的装饰器运行。

先运行f()之前的代码,下层装饰器优先运行;再运行f()代码;在运行f()之后的代码,依然是下层装饰器优先运行。

3.4 类装饰器

import time


class A():
    def __init__(self, t):
        print('实例化一个A类对象……')
        self.t = t

    def __call__(self, f):
        def inner_A(x):
            print('延迟{}秒后开始执行……'.format(self.t))
            time.sleep(self.t)
            print('{}函数开始运行……'.format(f.__name__))
            f(x)
            print('{}函数结束运行……'.format(f.__name__))
        return inner_A


@A(1)
def func(name):
    print('你好,{}!'.format(name))


if __name__ == '__main__':
    func('姚明')

四、 内饰装饰器

4.1 @property,@setter,@deleter

@property装饰器所装饰的函数可以像访问属性一样调用函数,注意,@property装饰器必须先于@setter,@deleter使用,且三者说装饰的函数必须同名。

class A():
    def __init__(self, v):
        print('实例化一个A类对象……')
        self.__value = v

    @property
    def value(self):
        print('取值时被调用')
        return self.__value

    @value.setter
    def value(self, value):
        print('赋值时被调用')
        self.__value = value

    @value.deleter
    def value(self):
        print('删除值时被调用……')
        del self.__value


if __name__ == '__main__':
    a = A(123)
    print('-------------')
    print('__value的值为:{}'.format(a.value))
    print('-------------')
    a.value = 234
    print('__value的值为:{}'.format(a.value))
    print('--------------')
    del a.value
    # print('__value的值为:{}'.format(a.value))  # 执行会报错

原文地址:https://www.cnblogs.com/qianslup/p/12193073.html