Python Decorator基础课程分享

简介: Python Decorator基础课程分享

Python的修饰器的英文名叫Decorator,当你看到这个英文名的时候,你可能会把其跟Design Pattern里的Decorator搞混了,其实这是完全不同的两个东西。在认识装饰器之前,我们先来点感性认识,看一个Python修饰器的Hello World的代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
下面是代码:文件名:hello.py
def hello(fn):
def wrapper():
print "hello, %s" % fn.name
fn()
print "goodby, %s" % fn.name
return wrapper

@hello
def foo():
print "i am foo"

foo()
当你运行代码,你会看到如下输出:

1
2
3
4
[chenaho@chenhao-air]$ python hello.py
hello, foo
i am foo
goodby, foo
你可以看到如下的东西:
  1)函数foo前面有个@hello的“注解”,hello就是我们前面定义的函数hello;
  2)在hello函数中,其需要一个fn的参数(这就用来做回调的函数);
  3)hello函数中返回了一个inner函数wrapper,这个wrapper函数回调了传进来的fn,并在回调前后加了两条语句。

Decorator 的本质

  对于Python的这个@注解语法糖- Syntactic Sugar 来说,当你在用某个@decorator来修饰某个函数func时,如下所示:

1
2
3
@decorator
def func():
pass
其解释器会解释成下面这样的语句:

1
func = decorator(func)
  了然,这不就是把一个函数当参数传到另一个函数中,然后再回调吗?是的,但是,我们需要注意,那里还有一个赋值语句,把decorator这个函数的返回值赋值回了原来的func。 根据《函数式编程》中的first class functions中的定义的,你可以把函数当成变量来使用,所以,decorator必需得返回了一个函数出来给func,这就是所谓的higher order function 高阶函数,不然,后面当func()调用的时候就会出错。 就我们上面那个hello.py里的例子来说,

1
2
3
@hello
def foo():
print "i am foo"
被解释成了:

1
foo = hello(foo)
是的,这是一条语句,而且还被执行了。你如果不信的话,你可以写这样的程序来试试看:

1
2
3
4
5
6
def fuck(fn):
print "fuck %s!" % fn.name[::-1].upper()

@fuck
def wfg():
pass
没了,就上面这段代码,没有调用wfg()的语句,你会发现, fuck函数被调用了,而且还很NB地输出了我们每个人的心声!

  再回到我们hello.py的那个例子,我们可以看到,hello(foo)返回了wrapper()函数,所以,foo其实变成了wrapper的一个变量,而后面的foo()执行其实变成了wrapper()。知道这点本质,当你看到有多个decorator或是带参数的decorator,你也就不会害怕了。

比如:多个decorator:

1
2
3
4
@decorator_one
@decorator_two
def func():
pass
相当于:

1
func = decorator_one(decorator_two(func))
比如:带参数的decorator:

//代码效果参考:https://v.youku.com/v_show/id_XNjQwNjg0Mjg4NA==.html

1
2
3
@decorator(arg1, arg2)
def func():
pass
相当于:

1
func = decorator(arg1,arg2)(func)
这意味着decorator(arg1, arg2)这个函数需要返回一个“真正的decorator”。

带参数及多个Decrorator

我们来看一个有点意义的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def makeHtmlTag(tag, args, **kwds):
def real_decorator(fn):
css_class = " class='{0}'".format(kwds["css_class"]) if "css_class" in kwds else ""
def wrapped(
args, kwds):
return "<"+tag+css_class+">" + fn(*args,
kwds) + "</"+tag+">"
return wrapped
return real_decorator

@makeHtmlTag(tag="b", css_class="bold_css")
@makeHtmlTag(tag="i", css_class="italic_css")
def hello():
return "hello world"

print hello()

输出:

hello world

在上面这个例子中,我们可以看到:makeHtmlTag有两个参数。所以,为了让 hello = makeHtmlTag(arg1, arg2)(hello) 成功,makeHtmlTag 必需返回一个decorator(这就是为什么我们在makeHtmlTag中加入了real_decorator()的原因),这样一来,我们就可以进入到 decorator 的逻辑中去了—— decorator得返回一个wrapper,wrapper里回调hello。看似那个makeHtmlTag() 写得层层叠叠,但是,已经了解了本质的我们觉得写得很自然。

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
初识Decorator

  Decorator,修饰符,是在Python2.4中增加的功能,也是pythoner实现元编程的最新方式,同时它也是最简单的元编程方式。为什么是“最简单”呢?是的,其实在Decorator之前就已经
有classmethod()和staticmethod()内置函数,但他们的缺陷是会导致函数名的重复使用(可以看看David Mertz的Charming Python: Decorators make magic easy ),
以下是摘自他本人的原文:

class C:
def foo(cls, y):
print "classmethod", cls, y
foo = classmethod(foo)

//代码效果参考:https://v.youku.com/v_show/id_XNjQwNjg0MjkwOA==.html

  是的,classmethod做的只是函数转换,但是它却让foo这个名字另外出现了2次。记得有一句话是:人类因懒惰而进步。Decorator的诞生,让foo少出现2次。

class C:
@classmethod
def foo(cls, y):
print "classmethod", cls, y

  读者也许已经想到Decorator在python中是怎么处理的了(如果还没头绪的,强烈建议先去看看limodou写的Decorator学习笔记 )。下面我列出4种用法。

单个 Decorator,不带参数

  设想一个情景,你平时去买衣服的时候,跟售货员是怎么对话的呢?售货员会先向你问好,然后你会试穿某件你喜爱的衣服。

def salesgirl(method):
def serve(args):
print "Salesgirl:Hello, what do you want?", method.name
method(
args)
return serve

@salesgirl
def try_this_shirt(size):
if size < 35:
print "I: %d inches is to small to me" %(size)
else:
print "I:%d inches is just enough" %(size)
try_this_shirt(38)

结果是:

Salesgirl:Hello, what do you want? try_this_shirt
I:38 inches is just enough

  这只是一个太简单的例子,以至一些“细节”没有处理好,你试穿完了好歹也告诉salesgirl到底要不要买啊。。。这样try_this_shirt方法需要改成带返回值
(假设是bool类型,True就是要买,False就是不想买),那么salesgirl中的serve也应该带返回值,并且返回值就是 method(*args)。

修改后的salesgirl

def salesgirl(method):
def serve(args):
print "Salesgirl:Hello, what do you want?", method.name
return method(
args)
return serve

@salesgirl
def try_this_shirt(size):
if size < 35:
print "I: %d inches is to small to me" %(size)
return False
else:
print "I:%d inches is just enough" %(size)
return True
result = try_this_shirt(38)
print "Mum:do you want to buy this?", result

结果是:

Salesgirl:Hello, what do you want? try_this_shirt
I:38 inches is just enough
Mum:do you want to buy this? True

现在我们的salesgirl还不算合格,她只会给客人打招呼,但是客人要是买衣服了,也不会给他报价;客人不买的话,也应该推荐其他款式!

会报价的salesgirl:

def salesgirl(method):
def serve(args):
print "Salesgirl:Hello, what do you want?", method.name
result = method(
args)
if result:
print "Salesgirl: This shirt is 50$."
else:
print "Salesgirl: Well, how about trying another style?"
return result
return serve

@salesgirl
def try_this_shirt(size):
if size < 35:
print "I: %d inches is to small to me" %(size)
return False
else:
print "I:%d inches is just enough" %(size)
return True
result = try_this_shirt(38)
print "Mum:do you want to buy this?", result

相关文章
|
3月前
|
供应链 数据挖掘 Serverless
【python】美妆类商品跨境电商数据分析(源码+课程论文+数据集)【独一无二】
【python】美妆类商品跨境电商数据分析(源码+课程论文+数据集)【独一无二】
【python】美妆类商品跨境电商数据分析(源码+课程论文+数据集)【独一无二】
|
3月前
|
机器学习/深度学习 数据采集 算法
【python】python基于微博互动数据的用户类型预测(随机森林与支持向量机的比较分析)(源码+数据集+课程论文)【独一无二】
【python】python基于微博互动数据的用户类型预测(随机森林与支持向量机的比较分析)(源码+数据集+课程论文)【独一无二】
|
3月前
|
机器学习/深度学习 供应链 数据可视化
【python】python化妆品销售logistic逻辑回归预测分析可视化(源码+课程论文+数据集)【独一无二】
【python】python化妆品销售logistic逻辑回归预测分析可视化(源码+课程论文+数据集)【独一无二】
|
3月前
|
数据采集 存储 数据可视化
【python】python古代玻璃制品的成分数据分析与可视化(源码+数据+课程论文)【独一无二】
【python】python古代玻璃制品的成分数据分析与可视化(源码+数据+课程论文)【独一无二】
|
3月前
|
数据可视化 数据挖掘 定位技术
【python】python商家会员数据分析可视化(源码+数据集+课程报告论文)
【python】python商家会员数据分析可视化(源码+数据集+课程报告论文)
|
6月前
|
缓存 测试技术 数据库
【Python 基础】什么是装饰器(decorator)?
【5月更文挑战第6天】【Python 基础】什么是装饰器(decorator)?
|
6月前
|
测试技术 Python
解释Python中的装饰器链(Decorator Chaining)。
解释Python中的装饰器链(Decorator Chaining)。
41 6
|
6月前
|
缓存 测试技术 Python
Python小知识 - 1. Python装饰器(decorator)
Python小知识 - 1. Python装饰器(decorator)