关于python装饰器

#Python 装饰器-part1
最近刚开始学习python,想着弄个博客记录一下自己学习的过程,同时也是为了总结一下.本人之前没有学过什么编程语言,所以理解有些问题有点苦手,最近就碰到一个很头大的东西叫做装饰器(Decorator),在stackoverflow看到一篇很好的文章,解析的很详细,很适合我这样的初学者.

阅读全文

Python的函数是对象

要理解装饰器,你首先需要理解在Python中,函数就是一个对象(object)这很重要,让我们简单看个例子:

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
def shout(word="yes"):
return word.capitalize()+"!"
print shout()
# outputs : 'Yes!'
# 我们可以把函数作为一个对象赋值给一个变量
scream = shout
# 注意到我们没有调用这个函数,是赋值给了一个变量
print scream()
# outputs : 'Yes!'
# 懒得翻译了自己看吧
# More than that, it means you can remove the old name 'shout', and
# the function will still be accessible from 'scream'
del shout
try:
print shout()
except NameError, e:
print e
#outputs: "name 'shout' is not defined"
print scream()
# outputs: 'Yes!

好了,记住这点,我们将会很快用到它.
Python函数另一个有趣的特性是,函数可以被定义在另一个函数里面.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def talk():
# You can define a function on the fly in "talk" ...
def whisper(word="yes"):
return word.lower()+"..."
# ... and use it right away!
print whisper()
# You call "talk", that defines "whisper" EVERY TIME you call it, then
# "whisper" is called in "talk".
talk()
# outputs:
# "yes..."
# But "whisper" DOES NOT EXIST outside "talk":
try:
print whisper()
except NameError, e:
print e
#outputs : "name 'whisper' is not defined"*
Python's functions are objects

##函数引用
好了,到这里了,接下来是有意思的部分,我们刚才看到函数都是对象:

  • can be assigned to a variable
  • can be assigned to a variable

这意味着函数可以返回另一个函数,让我们来看看☺

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
def getTalk(kind="shout"):
# We define functions on the fly
def shout(word="yes"):
return word.capitalize()+"!"
def whisper(word="yes") :
return word.lower()+"...";
# Then we return one of them
if kind == "shout":
# We don't use "()", we are not calling the function,
# we are returning the function object
return shout
else:
return whisper
# How do you use this strange beast?
# Get the function and assign it to a variable
talk = getTalk()
# You can see that "talk" is here a function object:
print talk
#outputs : <function shout at 0xb7ea817c>
# The object is the one returned by the function:
print talk()
#outputs : Yes!
# And you can even use it directly if you feel wild:
print getTalk("whisper")()
#outputs : yes...

但是,让我们想想,如果你可以返回一个函数,那么你也可以将函数作为参数传递

1
2
3
4
5
6
7
8
def doSomethingBefore(func):
print "I do something before then I call the function you gave me"
print func()
doSomethingBefore(scream)
#outputs:
#I do something before then I call the function you gave me
#Yes!

好了,现在你已经了解要理解装饰器的每件事.
装饰器就是能让你在不改变被装饰函数本身下,在其之前或之后执行相关代码,即对某个函数的封装
下面我们手工创建一个装饰器的例子.

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
# A decorator is a function that expects ANOTHER function as parameter
# 接收一个函数作为参数的函数并且最终返回自身的函数就是装饰器(我也不知道说的对不对)
def my_shiny_new_decorator(a_function_to_decorate):
# Inside, the decorator defines a function on the fly: the wrapper.
# This function is going to be wrapped around the original function
# so it can execute code before and after it.
def the_wrapper_around_the_original_function():
# Put here the code you want to be executed BEFORE the original
# function is called
print "Before the function runs"
# Call the function here (using parentheses)
a_function_to_decorate()
# Put here the code you want to be executed AFTER the original
# function is called
print "After the function runs"
# At this point, "a_function_to_decorate" HAS NEVER BEEN EXECUTED.
# We return the wrapper function we have just created.
# The wrapper contains the function and the code to execute before
# and after. It’s ready to use!
return the_wrapper_around_the_original_function
# Now imagine you create a function you don't want to ever touch again.
def a_stand_alone_function():
print "I am a stand alone function, don't you dare modify me"
a_stand_alone_function()
#outputs: I am a stand alone function, don't you dare modify me
# Well, you can decorate it to extend its behavior.
# Just pass it to the decorator, it will wrap it dynamically in
# any code you want and return you a new function ready to be used:
a_stand_alone_function_decorated = my_shiny_new_decorator(a_stand_alone_function)
a_stand_alone_function_decorated()
#outputs:
#Before the function runs
#I am a stand alone function, don't you dare modify me
#After the function runs

你肯定想你每次调用a_stand_alone_function的时候,实际上调用的是a_stand_alone_function_decorated,你只要重写a_stand_alone_function就好了

1
2
3
4
5
6
7
8
a_stand_alone_function = my_shiny_new_decorator(a_stand_alone_function)
a_stand_alone_function()
#outputs:
#Before the function runs
#I am a stand alone function, don't you dare modify me
#After the function runs
# And guess what? That’s EXACTLY what decorators do!

##装饰器揭秘
我们用装饰器来演示前面的例子

1
2
3
4
5
6
7
8
9
@my_shiny_new_decorator
def another_stand_alone_function():
print "Leave me alone"
another_stand_alone_function()
#outputs:
#Before the function runs
#Leave me alone
#After the function runs

是不是很简单,实际上,装饰器只做了一件事

1
another_stand_alone_function = my_shiny_new_decorator(another_stand_alone_function)

#装饰器进阶篇

##将参数传递给装饰器函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# It’s not black magic, you just have to let the wrapper
# pass the argument:
def a_decorator_passing_arguments(function_to_decorate):
def a_wrapper_accepting_arguments(arg1, arg2):
print "I got args! Look:", arg1, arg2
function_to_decorate(arg1, arg2)
return a_wrapper_accepting_arguments
# Since when you are calling the function returned by the decorator, you are
# calling the wrapper, passing arguments to the wrapper will let it pass them to
# the decorated function
@a_decorator_passing_arguments
def print_full_name(first_name, last_name):
print "My name is", first_name, last_name
print_full_name("Peter", "Venkman")
# outputs:
#I got args! Look: Peter Venkman
#My name is Peter Venkman

##装饰类里面的方法method
在python中,类里面的方法和函数其实差不多是一样的,唯一的不同在于方法默认接收第一个参数为(self)
让我们看看怎么装饰类里面的方法,只要记得第一个参数传为(self)就行了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def method_friendly_decorator(method_to_decorate):
def wrapper(self, lie):
lie = lie - 3 # very friendly, decrease age even more :-)
return method_to_decorate(self, lie)
return wrapper
class Lucy(object):
def __init__(self):
self.age = 32
@method_friendly_decorator
def sayYourAge(self, lie):
print "I am %s, what did you think?" % (self.age + lie)
l = Lucy()
l.sayYourAge(-3)
#outputs: I am 26, what did you think?
女人的年龄是秘密,哈哈哈

如果你想写一个接收任何参数的装饰器,我们可以使用*args,**kwargs

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
def a_decorator_passing_arbitrary_arguments(function_to_decorate):
# The wrapper accepts any arguments
def a_wrapper_accepting_arbitrary_arguments(*args, **kwargs):
print "Do I have args?:"
print args
print kwargs
# Then you unpack the arguments, here *args, **kwargs
# If you are not familiar with unpacking, check:
# http://www.saltycrane.com/blog/2008/01/how-to-use-args-and-kwargs-in-python/
function_to_decorate(*args, **kwargs)
return a_wrapper_accepting_arbitrary_arguments
@a_decorator_passing_arbitrary_arguments
def function_with_no_argument():
print "Python is cool, no argument here."
function_with_no_argument()
#outputs
#Do I have args?:
#()
#{}
#Python is cool, no argument here.
@a_decorator_passing_arbitrary_arguments
def function_with_arguments(a, b, c):
print a, b, c
function_with_arguments(1,2,3)
#outputs
#Do I have args?:
#(1, 2, 3)
#{}
#1 2 3
@a_decorator_passing_arbitrary_arguments
def function_with_named_arguments(a, b, c, platypus="Why not ?"):
print "Do %s, %s and %s like platypus? %s" %\
(a, b, c, platypus)
function_with_named_arguments("Bill", "Linus", "Steve", platypus="Indeed!")
#outputs
#Do I have args ? :
#('Bill', 'Linus', 'Steve')
#{'platypus': 'Indeed!'}
#Do Bill, Linus and Steve like platypus? Indeed!
class Mary(object):
def __init__(self):
self.age = 31
@a_decorator_passing_arbitrary_arguments
def sayYourAge(self, lie=-3): # You can now add a default value
print "I am %s, what did you think ?" % (self.age + lie)
m = Mary()
m.sayYourAge()
#outputs
# Do I have args?:
#(<__main__.Mary object at 0xb7d303ac>,)
#{}
#I am 28, what did you think?

待续(太特么长了)