python-黑魔法-装饰器

装饰器剖析

  1. 不带参数的装饰器
  2. 带参数的装饰器
  3. 类装饰器
  4. 利用functools.wrap 将wapped 的属性赋值给wapper
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# encoding: utf-8
"""
--------------------------------------
@describe
@version: 1.0
@project: websockets
@file: test.py
@author: yuanlang
@time: 2019-03-18 14:29
---------------------------------------
"""

# 先看看函数复制
def a():
pass


print(a)
x = a
print(x)


# 结论
# a方法地址给了 x
# 两个地址都是 a方法
print("---------------------------------------")

def log_track(func):
def wapper(*args, **kwargs):
print(func.__name__)
func(*args, **kwargs)

return wapper


def hello2():
pass


@log_track
def hello():
print("hello")


print(hello)
hello = wapper = log_track(hello) # 和 @log_track效果一样
print(hello)
print(hello2.__name__)
print(hello.__name__)


# 结论
# hello指针指向的hello函数地址进入到wapper作用域中,返回的wapper函数地址给 hello
print("---------------------------------------")



# 带参数的装饰器
def user_loggin(level):
print(level)

def decoration(func):
print(func.__name__)

def wrapper(*args,**kwargs):
print(func.__name__)
func(*args,**kwargs)
print("return wrapper")
return wrapper
print("return decoration")
return decoration


def foo():
return "foo"


func = decoration = user_loggin(level="debug")
print(func)
print("func.__name__ >>>>> ",func.__name__)
print("######################")
func = wrapper = user_loggin(level="debug")(foo)
print(func)
print("func.__name__ >>>>>",func.__name__)
print("######################")

@user_loggin(level="debug")
def foo2():
print("fool")
# 总结
# 带参数的装饰器比不带参数的装饰器多一层,需先解压出装饰器
print("---------------------------------------")


# 类装饰器
class Foo():

def __init__(self,func):
self.__func=func

def __call__(self, *args, **kwargs):
print("before call")
self.__func(*args,**kwargs)
print("after call")
return self.__func


def test():
print("test")


foo_obj=Foo(test)
print(foo_obj)
print("__call__",foo_obj())
print("######################")

print("__call__",foo_obj.__call__())
print("######################")


@Foo
def test1():
print("test1")

test1()
# 总结
# 类装饰器 实质是将 类的__call__地址 负值给要装饰的函数 test1=Foo(test1).__call__
print("---------------------------------------")


##
## 可以发现 需要被装饰的函数的 docstring、__name__ 被装饰器替代了
## 所以引出 functools.wraps,wraps本身也是一个装饰器,它能把原函数的元信息拷贝到装饰器函数中
##
from functools import wraps

def logged(func):

#func=decoration=wraps(func)(with_logging)
#wraps(func)解压并调用类装饰器
#func=partial().__call__
#update_wapper 将with_loggin 的某些参数负值给f return 的 with_logging 变为 f
@wraps(func)
def with_logging(*args, **kwargs):
print(func.__name__ + " was called")
return func(*args, **kwargs)

return with_logging


@logged
def f(x):
"""does some math"""
return x + x * x


print(f.__name__ ) # prints 'f'
print(f.__doc__ ) # prints 'does some math1'