天天看點

python裝飾器原理wraps(method)(self)_Python裝飾器了解與wraps

裝飾器

最簡單來說,裝飾器的作用是使用一個函數來處理另一個函數,用來擴充被裝飾的函數的功能。比如可以在函數前或函數後輸出修飾字元串,或在web中判斷是否登入等。

首先我們要知道函數的參數可以是另一個函數:1

2

3

4

5

6

7

8

9

10

11def protest(func):

def wrap():

print('Before func')

func()

print('After func')

return wrap()

def sayhello():

print('Hello,world!')

protest(sayhello)

輸出:1

2

3Before func

Hello,world!

After func

使用@函數裝飾器化後:1

2

3

4

5

6

7

8

9

10

11

12def protest(func):

def wrap():

print('Before func')

func()

print('After func')

return wrap()

@protest

def sayhello():

print('Hello,world!')

sayhello

輸出:1

2

3Before func

Hello,world!

After func

可以認為這兩個方式其實是一樣的,都是使用一個函數作為另一個函數的參數,一個函數封裝另一個函數。

使用wraps

很多時候也會使用functools的wraps來建立裝飾器,這是為了被封裝的函數能保留原來的内置屬性。

沒用wraps的修飾器:1

2

3

4

5

6

7

8

9

10

11

12

13def protest(func):

def wraptest(*args, **kwargs):

print('Before func')

func(*args, **kwargs)

return wrap

@protest

def sayhello(word):

print(word)

if __name__ == '__main__':

sayhello('hello, boy')

print(sayhello.__name__)

輸出:1

2

3Before func

hello, boy

wraptest

使用wraps的修飾器:1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18#!/bin/env python

from functools import wraps

def protest(func):

@wraps(func)

def wraptest(*args, **kwargs):

print('Before func')

func(*args, **kwargs)

return wrap

@protest

def sayhello(word):

print(word)

if __name__ == '__main__':

sayhello('hello, boy')

print(sayhello.__name__)

輸出:1

2

3Before func

hello, boy

sayhello

可以看到未使用wraps的sayhello函數的__name__輸出的是封裝函數wraptest的屬性,而不是被封裝函數自身的屬性,而使用wraps的輸出的是被封裝函數自身的屬性。

裝飾器用于類

裝飾器也可以用于類中函數,但如果要讓裝飾器使用執行個體方法,需要加上self,如:1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21from functools import wraps

def check_money(func):

@wraps(func)

def deal(self, *args, **kwargs):

if self.money < 1:

print('Not enough money!')

func(self, *args, **kwargs)

return deal

class Talk():

def __init__(self, money):

self.money = money

@check_money

def door(self):

return self.money

if __name__ == '__main__':

T = Talk(0)

T.door()