0. python functions
everything is python is an object.
1: assign function to a variable
def print_it(msg):
print msg
function1 = print_it
function1("hellow")
2: define function inside another function
def hellow(name):
def msg():
return "hellow "
return msg() + name
print hellow("sir")
3: function can be passed as parameters to another function(hign order funciton)
def hellow(name):
return "hellow" + name
def call_func(func):
time = " 2016"
return func(time)
print call_func(hellow)
1. python decorators
decorator is to add functionality to an existing code. it will modify another part of program at compile time. in fact, decorator is a higher order function which return a function.
let's look at a piece of code to record the runtime:
import timeit
import numpy as np
def time_record(func):
start = timeit.default_timer()
result = func()
end = timeit.default_timer()
print "run time is " + str(end - start)
return result
def sin_cos():
s = np.random.random(100)
return np.sin(s) + np.cos(s)
time_record(sin_cos)
# run time is 3.89412213906e-05
这里time_record
是一个高阶函数,它的参数是另一个函数sin_cos
。它起的作用是在sin_cos
运行的时候,计算所用的时间。或者从另一个角度看,对sin_cos
起了一个简单的装饰作用。这就是decorator
的含义。
如果要写成decorator
的样子,我们可以重新写为
import timeit
import numpy as np
def time_record(func):
start = timeit.default_timer()
result = func()
end = timeit.default_timer()
print "run time is " + str(end - start)
return result
@time_record
def sin_cos():
s = np.random.random(100)
return np.sin(s) + np.cos(s)
sin_cos
# run time is 5.46384578684e-05
这个时候就不需要再把sin_cos
作为参数传递给time_record
了,因为@time_record
已经做了这件事
2. decorator function has parameter
如果decorator
函数有参数,比如decorator(params)(inner_function)
,我们可以做同样的处理:
def time_record(name):
def decorator(func):
start = timeit.default_timer()
result = func()
end = timeit.default_timer()
print "Hellow " + name + ", run time is " + str(end - start)
return result
return decorator
@time_record("python-programming")
def sin_cos():
s = np.random.random(100)
return np.sin(s) + np.cos(s)
sin_cos
# Hellow python-programming, run time is 6.12795965935e-05
3. both decorator function and inner function have parameters
同样,如果装饰函数和目标函数都有参数,这个时候要多加一层:
def time_record(name):
def decorator(func):
def wrapper(*args, **kvargs):
start = timeit.default_timer()
result = func(*args, **kvargs)
end = timeit.default_timer()
print "current run function is %s" %(func.__name__)
print "Hellow " + name + ", run time is " + str(end - start)
return result
return wrapper
return decorator
@time_record("python-programming")
def my_sin(x):
return np.sin(x)
my_sin(np.random.random(100))
# current run function is sin
# Hellow python-programming, run time is 1.47916268816e-05
这样看起来没有什么问题,但是如果我们现在检查被decorator
装饰过的my_sin
的__name__
,我们会发现它的名字变成了wrapper。
print my_sin.__name__
# wrapper
我们需要调用Python内置的functools.wraps
def time_record(name):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kvargs):
start = timeit.default_timer()
result = func(*args, **kvargs)
end = timeit.default_timer()
print "current run function is %s" %(func.__name__)
print "Hellow " + name + ", run time is " + str(end - start)
return result
return wrapper
return decorator
@time_record("python-programming")
def my_sin(x):
return np.sin(x)
my_sin(np.random.random(100))
这时候再检查sin
的__name__
,就没有问题了:
print my_sin.__name__
# my_sin
4. 多层decorator
我们经常干这种事情,在输出的前后分别加上30个*和30个%. 我们可以用decorator
方便的实现这个功能:
def add_star(func):
def inner(*args, **kvargs):
print '*'*30
result = func(*args, **kvargs)
print '*'*30
return inner
def add_pct(func):
def inner(*args, **kvargs):
print '%'*30
result = func(*args, **kvargs)
print '%'*30
return inner
@add_star
@add_pct
def my_sin(x):
print np.sin(x)
my_sin(np.random.random(2))
# ******************************
# %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
# [ 0.48007195 0.32247404]
# %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
# ******************************