1. 程式人生 > >Python語言特性-面向切面程式設計AOP

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. 一個函式也可以被多個裝飾器所裝飾。