Python语言特性-面向切面编程AOP

我们先来解释一下AOP的概念。

AOP概念及作用

AOP 即面向切面编程,指扩展功能不修改源代码,将功能代码从业务逻辑代码中分离出来。

主要作用就是将类似于日志记录,性能统计,安全控制,事务处理,异常处理等重复性的代码块从业务逻辑代码中划分出来,对这些行为的分离。并且将它们独立到非知道业务逻辑的方法中,从而做到改变这些行为的时候不影响业务逻辑代码。

装饰器实现AOP

我们python中使用装饰器实现AOP。装饰器是一个很著名的设计模式,经常被用于有切面需求的场景,装饰器的作用就是为已经存在的对象添加额外的功能。

装饰器及闭包简介

装饰器 本身也是一个函数 ,这个函数以闭包的形式定义,在使用这个装饰器函数时,在被装饰的函数的前一行,使用 @装饰器函数名 形式来装饰。

闭包是指在一个函数中定义了一个另外一个函数,内函数里运用了外函数的临时变量,并且外函数的返回值是内函数的引用,这样就构成了一个闭包。 闭包的使用,可以隐藏内部函数的工作细节,只给外部使用者提供一个可以执行的内部函数的引用。

装饰器实例应用

写一个功能函数,实现一百万次的累加

def my_count():
    s = 0
    for i in range(1000001):
        s += i
    print('sum : ', s)

装饰器实现

import time

def count_time(func):
    def wrapper():      #wrapper 装饰
        start = time.time()
        func()
        end = time.time()
        print('共计执行:%s 秒'%(end - start)) # 使用%d显示,取整后是0秒,因为不到一秒
    return wrapper

@count_time     # 这实际就相当于解决方法3中的 my_count = count_tiem(my_count)
def my_count():
    s = 0
    for i in range(10000001):
        s += i
    print('sum : ', s)

my_count()

这样实现的好处是,定义好了闭包函数后。只需要通过 @xxx 形式的装饰器语法,将 @xxx 加到要装饰的函数前即可。使用者在使用时,根本不需要知道被装饰了。只需要知道原来的函数功能是什么即可。

在执行 @xxx 时 ,实际就是将 原函数传递到闭包中,然后原函数的引用指向闭包返回的装饰过的内部函数的引用。

类实现装饰器

在类中通过使用 init 和 __call__方法来实现

  class Test(object):
        # 通过初始化方法,将要被装饰的函数传进来并记录下来
        def __init__(self, func):
            self.__func = func
        # 重写 __call__ 方法来实现装饰内容
        def __call__(self, *args, **kwargs):
            print('wrapper context')
            self.__func(*args, **kwargs)


    # 实际通过类的魔法方法call来实现
    @Test  # --> show = Test(show) show由原来引用函数,装饰后变成引用Test装饰类的对象
    def show():
        pass


    show()  # 对象调用方法,实际上是调用魔法方法call,实现了装饰器

函数被多个装饰器所装饰

一个函数在使用时,通过一个装饰器来扩展,可能并不能完成达到预期。

Python 中允许一个函数被多个装饰器所装饰。

# 装饰器1
def setFunc1(func):
    def wrapper1(*args, **kwargs):
        print('Wrapper Context 1 Start...')
        func(args, kwargs)
        print('Wrapper Context 1 End...')
    return wrapper

# 装饰器2
def setFunc2(func):
    def wrapper2(*args, **kwargs):
        print('Wrapper Context 2 Start...')
        func(args, kwargs)
        print('Wrapper Context 2 End...')
    return wrapper


#一个函数被装饰了两次
@setFunc1
@setFunc2
def show(*args, **kwargs):
    print('Show Run ...')

show()

执行结果

Wrapper Context 1 Start...
Wrapper Context 2 Start...
Show Run ...
Wrapper Context 2 End...
Wrapper Context 1 End...

这个装饰器是从上到下执行,从下向上装饰,
在web框架中的钩子函数和中间件都有使用。

总结

  1. 函数可以像普通变量一样,做为函数的参数或返回值进行传递。
  2. 函数内部可以定义另外一个函数,这样做的目的可以隐藏函数功能的实现。
  3. 闭包实际也是一种函数定义形式。
  4. 闭包定义规则是在外部函数中定义一个内部函数,内部函数使用外部函数的变量,并返回内部函数的引用。
  5. 装饰器的作用是在不改变现有函数基础上,为函数增加功能。
  6. 通过在已有函数前,通过@闭包函数名的形式来给已有函数添加装饰器。
  7. 一个装饰器可以为多个函数提供装饰功能,只需要在被装饰的函数前加 @xxx 即可。
  8. 通过类也可以实现装饰器效果,需要重写 initcall 函数。
  9. 类实现的装饰器在装饰函数后,原来的函数引用不在是函数,而是装饰类的对象。
  10. 一个函数也可以被多个装饰器所装饰。

你可能感兴趣的:(Python语言特性)