当前位置:   article > 正文

Python高级编程教程(一)| 第一章 装饰器类_定义子对象集合的操作接口,通过装饰器类获取子对象,提供组件对象集合类

定义子对象集合的操作接口,通过装饰器类获取子对象,提供组件对象集合类

第一章 装饰器

简介

用于封装函数或者类代码的工具。其核心也就是一个可以接受调用也可以返回调用的调用。无非就是一个函数(或调用),该函数接受被装饰的函数作为其位置参数。装饰器通过使用该参数来执行一些操作,然后返回原始参数或者其他的一些调用。
装饰器类也就是接受另一个函数作为参数,并用其完成一些操作的函数。
装饰器类:通常是接受被装饰的可调用函数作为唯一参数,并返回一个可调用函数。
示例:

def debug(func):
    def wrapper():
        print("[DEBUG]: enter {}()".format(func.__name__))
        return func()
    return wrapper

@debug
def say_hello():
    print("hello!")

if __name__ == '__main__':
    say_hello()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

say_hello()函数的定义前加上@debug,相当于执行了:say_hello=debug(say_hello)
也就是说:

当装饰器应用到装饰函数时(而不是调用装饰器),会执行装饰代码本身。

练习: 计算任意函数运行时间

import time
def decorator(func):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        func()
        end_time = time.time()
        print(end_time - start_time)
    return wrapper

@decorator
def func():
    time.sleep(0.8)

func() # 函数调用
# 输出:0.800644397735595
if __name__ == '__main__':
    func()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

这里的内层函数-wrapper,其实就相当于闭包函数,它起到装饰给定函数的作用,wrapper参数为*args, **kwargs。*args表示的参数以列表的形式传入;**kwargs表示的参数以字典的形式传入
什么函数可以被称为闭包函数呢?主要是满足两点:函数内部定义的函数;引用了外部变量但非全局变量。

类装饰器

在Python中,一切皆对象,函数和类本质没有什么不一样。[装饰器函数、装饰器类]
装饰器函数其实是这样一个接口约束,它必须接受一个callable对象作为参数,然后返回一个callable对象。在Python中一般callable对象都是函数,但也有例外。只要某个对象重载了__call__()方法,那么这个对象就是callable的。
回到装饰器上的概念上来,装饰器要求接受一个callable对象,并返回一个callable对象(不太严谨,详见后文)。那么用类来实现也是也可以的。我们可以让类的构造函数__init__()接受一个函数,然后重载__call__()并返回一个函数,可将一个类实例变成一个可调用对象,也可以达到装饰器函数的效果。

class Decorator(object):
    def __init__(self, f):
        self.f = f
    def __call__(self):
        print("decorator start")
        self.f()
        print("decorator end")

@Decorator
def func():
    print("func")

func()
#运行结果:
#decorator start
#func
#decorator end
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

解释:

p = Decorator(func) p是类Decorator的一个实例
p() 实现了__call__()方法后,p可以被调用
要使用类装饰器必须实现类中的__call__()方法,就相当于将实例变成了一个方法。

多个装饰器

当有多个装饰器修饰一个函数的时候,装饰器的执行顺序是由近及远

Python装饰器库-functools

def decorator(func):
    def inner_function():
        pass
    return inner_function

@decorator
def func():
    pass
print(func.__name__)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

执行的结果:
inner_function

也就是说,代码执行的不是func,而是直接调用的inner_function函数。
需要借助functools模块
因为返回的那个inner_function()函数名字就是inner_function,所以,需要把原始函数的__name__等属性复制到inner_function()函数中,否则,有些依赖函数签名的代码执行就会出错。
不需要编写inner_function.__name__ = func.__name__这样的代码,Python内置的functools.wraps就是干这个事的
修改后:

from functools import wraps
def decorator(func):
    @wraps(func) 
    def inner_function():
        pass
    return inner_function

@decorator
def func():
    pass

print(func.__name__)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

运行结果:
func

应用场景

  • 某个功能在你原有的函数基础上,添加了新的功能,而你又不希望去修改原有的函数定义,从而定义的新的函数。这种在代码运行期间动态增加功能的方式,称之为装饰器。
  • Django中使用@login_required作为装饰器
  • Flask中使用@app.route充当指定URI路由
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/213309
推荐阅读
相关标签
  

闽ICP备14008679号