python 中面向切面編程AOP和裝飾器

相信學過java框架的對AOP應該是很熟悉了,那什么是面向切面編程AOP呢?

AOP

簡言之、這種在運行時,編譯時,類和方法加載時,動態(tài)地將代碼切入到類的指定方法、指定位置上的編程思想就是面向切面的編程。

我們管切入到指定類指定方法的代碼片段稱為切面,而切入到哪些類、哪些方法則叫切入點。有了AOP,我們就可以把幾個類共有的代碼,抽取到一個切片中,等到需要時再切入對象中去,從而改變其原有的行為。

優(yōu)點是:這樣的做法,對原有代碼毫無入侵性

裝飾器

裝飾器是一個很著名的設計模式,經(jīng)常被用于有切面需求的場景,較為經(jīng)典的有插入日志、性能測試、事務處理等。裝飾器是解決這類問題的絕佳設計,有了裝飾器,我們就可以抽離出大量函數(shù)中與函數(shù)功能本身無關的雷同代碼并繼續(xù)重用。

概括的講,裝飾器的作用就是為已經(jīng)存在的對象添加額外的功能。

要想明白裝飾器首先要明白一個概念即函數(shù)即是對象。
不明白的可以看看這篇文章

python 函數(shù)的本質(zhì)理解

函數(shù)就是對象.因此,對象:

  • 可以賦值給一個變量
  • 可以在其他函數(shù)里定義
  • 函數(shù)可以返回另一個函數(shù)
  • 函數(shù)作為參數(shù)傳遞

自己動手實現(xiàn)裝飾器

# 裝飾器就是把其他函數(shù)作為參數(shù)的函數(shù)
def my_new_decorator(a_function_to_decorate):

    # 在函數(shù)里面,裝飾器在運行中定義函數(shù): 包裝.
    # 這個函數(shù)將被包裝在原始函數(shù)的外面,所以可以在原始函數(shù)之前和之后執(zhí)行其他代碼..
    def the_wrapper_function():

        # 把要在原始函數(shù)被調(diào)用前的代碼放在這里
        print "Before the function runs"

        # 調(diào)用原始函數(shù)(用括號)
        a_function_to_decorate()

        # 把要在原始函數(shù)調(diào)用后的代碼放在這里
        print "After the function runs"

    # 在這里"a_function_to_decorate" 函數(shù)永遠不會被執(zhí)行
    # 在這里返回剛才包裝過的函數(shù)
    # 在包裝函數(shù)里包含要在原始函數(shù)前后執(zhí)行的代碼.
    return the_wrapper_function

# 加入你建了個函數(shù),不想修改了
def a_stand_alone_function():
    print "I am a stand alone function, don't you dare modify me"

a_stand_alone_function()
#輸出: I am a stand alone function, don't you dare modify me

# 現(xiàn)在,你可以裝飾它來增加它的功能
# 把它傳遞給裝飾器,它就會返回一個被包裝過的函數(shù).

a_function_decorated = my_new_decorator(a_stand_alone_function)
# 執(zhí)行
a_function_decorated()
#輸出s:
#Before the function runs
#I am a stand alone function, don't you dare modify me
#After the function runs

真實裝飾器

@my_new_decorator
def another_stand_alone_function():
    print "Leave me alone"

another_stand_alone_function()
#輸出:
#Before the function runs
#Leave me alone
#After the function runs

從這里可以看出@decorator就是下面的簡寫:

another_stand_alone_function = my_new_decorator(another_stand_alone_function)

在裝飾器函數(shù)里傳入?yún)?shù)

def a_decorator_passing_arguments(function_to_decorate):
    def a_wrapper_accepting_arguments(arg1, arg2):
        print "I got args! Look:", arg1, arg2
        function_to_decorate(arg1, arg2)
    return a_wrapper_accepting_arguments

# 當你調(diào)用裝飾器返回的函數(shù)時,也就調(diào)用了包裝器,把參數(shù)傳入包裝器里,
# 它將把參數(shù)傳遞給被裝飾的函數(shù)里.

@a_decorator_passing_arguments
def print_full_name(first_name, last_name):
    print "My name is", first_name, last_name

print_full_name("Peter", "Venkman")
# 輸出:
#I got args! Look: Peter Venkman
#My name is Peter Venkman

把參數(shù)傳給裝飾器

# 裝飾器就是一個'平常不過'的函數(shù)
def my_decorator(func):
    print "I am an ordinary function"
    def wrapper():
        print "I am function returned by the decorator"
        func()
    return wrapper

# 因此你可以不用"@"也可以調(diào)用他

def lazy_function():
    print "zzzzzzzz"

decorated_function = my_decorator(lazy_function)
#輸出: I am an ordinary function

# 之所以輸出 "I am an ordinary function"是因為你調(diào)用了函數(shù),
# 并非什么魔法.

@my_decorator
def lazy_function():
    print "zzzzzzzz"

#輸出: I am an ordinary function

這里調(diào)用decorated_function()才會輸出裝飾器里面的方法,建一個裝飾器.它只是一個新函數(shù),去掉中間變量他就會變?yōu)檎嬲难b飾器,那么如何去掉中間變量

def decorator_maker_with_arguments(decorator_arg1, decorator_arg2):

    print "I make decorators! And I accept arguments:", decorator_arg1, decorator_arg2

    def my_decorator(func):
        # 這里傳遞參數(shù)的能力是借鑒了 closures.
        # 如果對closures感到困惑可以看看下面這個:
        # http://stackoverflow.com/questions/13857/can-you-explain-closures-as-they-relate-to-python
        print "I am the decorator. Somehow you passed me arguments:", decorator_arg1, decorator_arg2

        # 不要忘了裝飾器參數(shù)和函數(shù)參數(shù)!
        def wrapped(function_arg1, function_arg2) :
            print ("I am the wrapper around the decorated function.\n"
                  "I can access all the variables\n"
                  "\t- from the decorator: {0} {1}\n"
                  "\t- from the function call: {2} {3}\n"
                  "Then I can pass them to the decorated function"
                  .format(decorator_arg1, decorator_arg2,
                          function_arg1, function_arg2))
            return func(function_arg1, function_arg2)

        return wrapped

    return my_decorator

@decorator_maker_with_arguments("Leonard", "Sheldon")
def decorated_function_with_arguments(function_arg1, function_arg2):
    print ("I am the decorated function and only knows about my arguments: {0}"
           " {1}".format(function_arg1, function_arg2))

decorated_function_with_arguments("Rajesh", "Howard")
#輸出:
#I make decorators! And I accept arguments: Leonard Sheldon
#I am the decorator. Somehow you passed me arguments: Leonard Sheldon
#I am the wrapper around the decorated function.
#I can access all the variables
#   - from the decorator: Leonard Sheldon
#   - from the function call: Rajesh Howard
#Then I can pass them to the decorated function
#I am the decorated function and only knows about my arguments: Rajesh Howard

看到了嗎?我們用一個函數(shù)調(diào)用"@“

幾個例子

def addTips(fun):
    def wrap(*arg,**kwargs):
        print("this is oper before")
        result = fun(*arg,**kwargs)
        #return result
        print("this is oper after")
        return result
    return wrap
@addTips
def add():
    print("進行添加的操作")
    
add()
this is oper before
進行添加的操作
this is oper after
@addTips
def add1(x,y):
    print(x+y)
add1(2,6)
this is oper before
8
this is oper after
@addTips
def add2(x,y):
    return x+y

print(add2(2,3))
this is oper before
this is oper after
5
def addTips(i):
    def wrap1(fun):
        def wrap(*arg,**kwargs):
            print("this is oper before")
            result = 0
            if i > 10:
                result = fun(*arg,**kwargs)
            else:
                print("you not have any auth")
            #return result
            print("this is oper after")
            return result
        return wrap
    return wrap1

@addTips(11)
def add(x,y):
    print(x+y)
    
add(2,3)
this is oper before
5
this is oper after

裝飾器的知識點

  • 裝飾器使函數(shù)調(diào)用變慢了.一定要記住.

  • 裝飾器不能被取消(有些人把裝飾器做成可以移除的但是沒有人會用)所以一旦一個函數(shù)被裝飾了.所有的代碼都會被裝飾.

  • Python自身提供了幾個裝飾器,像property, staticmethod.

  • Django用裝飾器管理緩存和試圖的權限.

  • Twisted用來修改異步函數(shù)的調(diào)用.

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容