python 基礎裝飾器入門

2021-09-27 23:45:37 字數 4742 閱讀 5209

1、裝飾器語法糖

python提供了@符號作為裝飾器的語法糖,使我們更方便的應用裝飾函式。但使用語法糖要求裝飾函式必須return乙個函式物件。因此我們將上面的func函式使用內嵌函式包裹並return。

裝飾器相當於執行了裝飾函式use_loggin後又返回被裝飾函式bar,因此bar()被呼叫的時候相當於執行了兩個函式。等價於use_logging(bar)()

1

defuse_logging

(func):2

def_deco()

:3print

("%s is running"

% func.__name__)

4 func()5

return _deco

6 @use_logging

7def

bar():

8print

('i am bar'

)9 bar(

)

2、對帶引數的函式進行裝飾現在我們的引數需要傳入兩個引數並計算值,因此我們需要對內層函式進行改動傳入我們的兩個引數a和b,等價於use_logging(bar)(1,2)

1

defuse_logging

(func):2

def_deco

(a,b):3

print

("%s is running"

% func.__name__)

4 func(a,b)

5return _deco

6 @use_logging

7def

bar(a,b):8

print

('i am bar:%s'

%(a+b)

)9 bar(1,

2)

我們裝飾的函式可能引數的個數和型別都不一樣,每一次我們都需要對裝飾器做修改嗎?這樣做當然是不科學的,因此我們使用python的變長引數*args和**kwargs來解決我們的引數問題。

3、函式引數數量不確定

不帶引數裝飾器版本,這個格式適用於不帶引數的裝飾器。

經過以下修改我們已經適應了各種長度和型別的引數。這個版本的裝飾器已經可以任意型別的無引數函式。

1

defuse_logging

(func):2

def_deco

(*args,

**kwargs):3

print

("%s is running"

% func.__name__)

4 func(

*args,

**kwargs)

5return _deco

6 @use_logging

7def

bar(a,b):8

print

('i am bar:%s'

%(a+b)

)9 @use_logging

10def

foo(a,b,c):11

print

('i am bar:%s'

%(a+b+c)

)12 bar(1,

2)13 foo(1,

2,3)

4、裝飾器帶引數帶引數的裝飾器,這個格式適用於帶引數的裝飾器。

某些情況我們需要讓裝飾器帶上引數,那就需要編寫乙個返回乙個裝飾器的高階函式,寫出來會更複雜。比如:

1

#! /usr/bin/env python

2# -*- coding:utf-8 -*-

3# __author__ = "tkq"

4def

use_logging

(level):5

def_deco

(func):6

def__deco

(*args,

**kwargs):7

if level ==

"warn":8

print

"%s is running"

% func.__name__

9return func(

*args,

**kwargs)

10return __deco

11return _deco

12 @use_logging(level=

"warn")13

defbar

(a,b):14

print

('i am bar:%s'

%(a+b)

)15 bar(1,

3)16# 等價於use_logging(level="warn")(bar)(1,3)

5、functools.wraps使用裝飾器極大地復用了**,但是他有乙個缺點就是原函式的元資訊不見了,比如函式的docstring、name、引數列表,先看例子:

1

defuse_logging

(func):2

def_deco

(*args,

**kwargs):3

print

("%s is running"

% func.__name__)

4 func(

*args,

**kwargs)

5return _deco

6 @use_logging

7def

bar():

8print

('i am bar')9

print

(bar.__name__)

10 bar()11

#bar is running

12#i am bar

13#_deco

14#函式名變為_deco而不是bar,這個情況在使用反射的特性的時候就會造成問題。因此引入了functools.wraps解決這個問題。

使用functools.wraps:

1

import functools

2def

use_logging

(func)

:3 @functools.wraps(func)

4def

_deco

(*args,

**kwargs):5

print

("%s is running"

% func.__name__)

6 func(

*args,

**kwargs)

7return _deco

8 @use_logging

9def

bar():

10print

('i am bar')11

print

(bar.__name__)

12 bar()13

#result:

14#bar is running

15#i am bar

16#bar ,這個結果是我們想要的。ok啦!

6、實現帶引數和不帶引數的裝飾器自適應

1

import functools

2def

use_logging

(arg):3

ifcallable

(arg)

:#判斷參入的引數是否是函式,不帶引數的裝飾器呼叫這個分支

4 @functools.wraps(arg)

5def

_deco

(*args,

**kwargs):6

print

("%s is running"

% arg.__name__)

7 arg(

*args,

**kwargs)

8return _deco

9else

:#帶引數的裝飾器呼叫這個分支

10def

_deco

(func)

:11 @functools.wraps(func)

12def

__deco

(*args,

**kwargs):13

if arg ==

"warn":14

print

"warn%s is running"

% func.__name__

15return func(

*args,

**kwargs)

16return __deco

17return _deco

18 @use_logging(

"warn")19

# @use_logging

20def

bar():

21print

('i am bar')22

print

(bar.__name__)

23 bar(

)

python基礎 裝飾器

裝飾器本質就是函式,功能是為其他函式新增附加功能。原則 不修改被修飾函式的源 不修改被修飾函式的呼叫方式 裝飾器的知識儲備 裝飾器 高階函式 函式巢狀 閉包 import time 定義乙個裝飾器計算函式執行時間 def timer func start time time.time res fun...

python基礎 裝飾器

裝飾器形成的過程 最簡單的裝飾器 有返回值的 有乙個引數 萬能引數 裝飾器的作用 原則 開放封閉原則 語法糖 裝飾器的固定模式 import time print time.time 獲取當前時間 time.sleep 10 讓程式在執行到這個位置的時候停一會兒 def timmer f 裝飾器函式...

Python基礎 裝飾器

裝飾器是程式開發中經常會用到的乙個功能,程式開發的基礎知識,用好了裝飾器,開發效率如虎添翼,所以這也是python面試中必問的問題,但對於好多初次接觸這個知識的人來講,這個功能有點繞,這個都不會,別跟人家說你會python,看了下面的文章,保證你學會裝飾器。裝飾器 decorator 首先我們需要知...