源碼時代python乾貨分享| python裝飾的神奇魅力初體驗

簡單的裝飾器

1.1.1.一個最簡單的裝飾行爲

裝飾器的一個特色是:在執行原函數的基礎上,增長內容。
我們舉個簡單的例子:
咱們能夠把它用做日誌打印器,在執行函數前,會有禮貌的告知你一下
「親愛的coder,我要執行了」
在執行結束後,也會告知各位coder。
是否是頗有趣?
那麼,我們如何執行原函數那?
✔ 把原函數的名字交給裝飾函數,裝飾函數就具有了執行老函數的能力。python

舊函數,待裝飾的函數app

def fun():
    print('我是老函數')

def factory(old_fun):
    print('='*20)
    old_fun()
    print('='*20)

factory(fun)

1.1.2.完善裝飾行爲

❓ 上面的裝飾行爲還有哪些問題?
◇ 須要經過裝飾工廠來調用原函數,原來調用這個功能的業務部門,將大面積修改代碼;
❓ 那麼如何改進這個問題那?
如何設計一個方式,在不改變原函數名稱的狀況下,調用時也執行裝飾工廠那。
◇ old_name = factory(old_name)ide

def fun():
    print("我是fun")

def factory(a):
    def tmp():
        print("="*10)
        a()
        print("="*10)
    return tmp

fun = factory(fun)
fun()

1.1.3.python的裝飾器語法糖

old_name = factory(old_name)這句話就是生成裝飾器的核心語句。爲了不每次都寫這樣的無腦代碼,python提供了一個便捷的寫法,咱們稱之爲語法糖。
語法糖的寫法:
· 找到要裝飾的函數
· 在上面寫上@,而後跟裝飾器函數的名稱br/>@decortate
def fun():
print('in fun() ...')
1.1.4.總結
python的裝飾器寫法思路:
1.定義一箇中介函數,該函數命名爲裝飾行爲,接收一個可調用對象
def get_timer(fn):
pass
2.在中介函數內部實現裝飾行爲函數
def get_timer(fn):
def wrapper():
... ... # 裝飾代碼實現
3.在中介函數最後返回裝飾行爲的函數名:
def get_timer(fn):
def wrapper():
... ... # 裝飾代碼實現
return wrapperbr/>【注意】:返回的是函數名,而不是函數調用
4.在須要被裝飾的函數前,定義@裝飾器名稱
@get_timer
def fun():
pass函數

1.2.python裝飾器的幾種形式

1.2.1.無參數裝飾器
Demo1: 增長函數何時運行的功能:設計

import time

def time_fun(func):
    def my_time():
        print(f"{func.__name__} running at {time.ctime()}")
        func()
    return my_time

@time_fun
def fun1():
    print("+++++++++")

fun1()
time.sleep(2)
fun1()

1.2.2.被裝飾函數有參數

裝飾器的核心是內部函數的行爲被重命名;
內部函數的形式要知足原函數形式;日誌

import time

def time_fun(func):
    def my_time(arg1):                      # 內部函數裏預留接口
        print(f"{func.__name__} running at {time.ctime()}")
        func(arg1)                          # 原函數傳遞參數
    return my_time

@time_fun
def fun1(arg1):
    print("+++++{}++++".format(arg1))

fun1(10)
time.sleep(2)
fun1(10)

1.2.3.被裝飾函數有不定參數和返回值

原函數有返回值,內部裝飾函數也接收返回值進行返回。
import timecode

def time_fun(func):
    def my_time(*args, **kwargs):
        print(f"{func.__name__} running at {time.ctime()}")
        func(*args, **kwargs)
    return my_time

@time_fun
def fun1(arg1, arg2, name):
    print("+++++{},{},{}++++".format(arg1, arg2, name))

fun1(10, 20, name='rocky')
time.sleep(2)
fun1(10, 20, name='jim')

1.2.4.改變裝飾器行爲(給裝飾器傳參數)

在裝飾器中,咱們也有一種需求,根據傳入的參數不一樣,裝飾的行爲方式也會不一樣,那麼如何定義這種裝飾器那。
首先再理解裝飾器的語法:orm

@time_fun
def fun1(arg1, arg2, name):
    print("+++++{},{},{}++++".format(arg1, arg2, name))
原材料名稱= 裝飾器名稱(原材料名稱)
@time_fun(「itsource」)
def fun1(arg1, arg2, name):
    print("+++++{},{},{}++++".format(arg1, arg2, name))
fun1 = time_fun(「itsource」)(fun1)

這樣來看,必需要保證time_fun(「itsource」)返回的內容剛好是標準的裝飾器就能夠知足了。
import time對象

def time_fun(flags):
    def time_arg(func):
        def my_time(*args, **kwargs):
            print(f"{func.__name__} running at {time.ctime()}")
            print("the flags is {}".format(flags))
            return func(*args, **kwargs)
        return my_time
    return time_arg

@time_fun("itsource")
def fun1(arg1, arg2, name):
    print("+++++{},{},{}++++".format(arg1, arg2, name))

fun1(10, 20, name='rocky')
time.sleep(2)
fun1(10, 20, name='jim')

1.2.5.用類來定義裝飾器(瞭解)

❓ 可執行對象到底是什麼?
✔ 具備call方法的對象空間,就稱之爲可執行對象,每定義一個函數,就至關於在空間中定義了call方法。
❓ 如何利用類來實現裝飾器
@Test # fun = Test(fun)
def fun():
pass
Test的init方法應該接收被裝飾函數的名稱
調用fun()實際就是調用了Test類的call方法
class Test():
def init(self, fn):
self.old_fun = fn接口

def __call__(self,):
    ... ...                     # 裝飾內容
    ret = self.old_fun()

@Test
def fun(a, b, name):
pass
fun()

1.3.多層裝飾

在實際開發時,一個原函數,可使用多個裝飾函數進行修飾,這種行爲就稱之爲多層裝飾。
對於多層裝飾,要理解他的執行過程。

def bold(fn):
    def wrapper():
        return f'<b>{fn()}</b>'
return wrapper

def italic(fn):
    def wrapper():
        return f'<i>{fn()}</i>'
    return wrapper

@italic
@bold
def hello():
    return 'Hello World'

print(hello())

【結果】:<i><b>Hello World</b></i>1.4.總結裝飾器實際也是一個函數(可調用對象);接收一個老函數的名稱;返回新函數的名稱;在新函數裏調用老函數;

相關文章
相關標籤/搜索