一 装饰器
def now():
print '2016.12.21'
f = now #说明函数也是一个对象
f()
2016.12.21
可以通过__name__拿到函数的名字
now.__name__
'now'
f.__name__
'now'
如何在调用函数前后自动打印日志,但又不修改now()函数的定义呢?这种在运行器件动态增加功能的方式,称作装饰器(Decorator)
1 装饰器的使用
def log(func):#这里log就是一个装饰器,所以它接受一个函数作为参数,并返回一个函数
def wrapper(*args,**kw):
print 'call %s():' % func.__name__
return func(*args,**kw)
return wrapper
接着我们用python的@语法,把decorator置于函数的定义处:
@log#把装饰器置于函数定义处后,每次调用函数就等于直接调用装饰器函数了,好厉害的函数啊,么么哒~
def now():
print '2016-12-21'
now()
call now():
2016-12-21
就相当于now = log(now),即每次调用函数就等于直接调用装饰器函数了,好厉害的函数啊,么么哒~
2 嵌套的时候传入额外的参数
def log(text):
def decorator(func):
def wrapper(*args, **kw):
print '%s %s():' % (text, func.__name__)
return func(*args, **kw)
return wrapper
return decorator
@log('execute')
def now():
print 'i love you!'
now()
execute now():
i love you!
相当于now = log(‘execute’)(now)
3 有个小问题
now.__name__
'wrapper'
这个时候now的name居然变成了wrapper,是因为前面return的是wrapper,为了不造成错误,所以我们还需要修改now的name,并且不需要编写wrapper.name = func.name这样的代码,Python内置的functools.wraps就是干这个事的,所以,一个完整的decorator的写法如下:
#不带参数的装饰器
import functools
def log(func):
@functools.wraps(func)
def wrapper(*args, **kw):
print 'call %s():' % func.__name__
return func(*args, **kw)
return wrapper
@log
def cheng():
print 'i love you~~!'
cheng()
call cheng():
i love you~~!
cheng.__name__
'cheng'
函数名字变回来咯,么么哒~ 原谅我秀恩爱哈哈哈哈
#带参数的装饰器
import functools
def log(text):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kw):
print '%s %s():' % (text, func.__name__)
return func(*args, **kw)
return wrapper
return decorator
@log('cheng')
def hu():
print '1314~~'
hu()
cheng hu():
1314~~
hu.__name__
'hu'
名字也是变回来了的(^__^) 嘻嘻……
decorator可以增强函数的功能,定义起来虽然有点复杂,但使用起来非常灵活和方便。
二 高阶函数
1 函数是对象,函数名是变量
abs(-10)
10
a = abs#将函数这个对象赋值给a这个变量
a(-10)#然后a也可以最为函数了,即a也是指向这个对象了
10
a已经指向abs里面的那个对象了,其实abs只是指向求绝对值的那个对象的一个变量名而已,那么就意味着我可以将abs指向其他对象,那么它将不能求绝对值了,代码如下:
abs = 10
abs(-10)#将abs指向其他对象,那么它将不能求绝对值了,所以报错
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-34-325d119fa582> in <module>()
1 abs = 10
----> 2 abs(-10)#将abs指向其他对象,那么它将不能求绝对值了,所以报错
TypeError: 'int' object is not callable
2 函数作为参数
abs = a #赶紧把abs变回来
def add(x,y,f):
return f(x) + f(y)
add(-5,-10,abs)
15
三 map/reduce,匿名函数,返回函数,偏函数等等
1 map/reduce
def f(x):
return x*x
map(f,[1,2,3,4,5,6,7,8,9])
[1, 4, 9, 16, 25, 36, 49, 64, 81]
可以看出map的作用就是将传入的函数依次作用到序列的每个元素
def add(x,y):
return x + y
reduce(add,[1,3,5,7,9])
25
这是怎么求和的呢?原来是这样:reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
2 匿名函数
map(lambda x: x * x, [1, 2, 3, 4, 5, 6, 7, 8, 9])
[1, 4, 9, 16, 25, 36, 49, 64, 81]
即lambda x: x * x实际就是一个函数:
def f(x):
return x * x
3 返回函数
def lazy_sum(*args):
def sum():
ax = 0
for n in args:
ax = ax + n
return ax
return sum
f = lazy_sum(1,2,3,4)
f#返回的只是一个函数
<function __main__.sum>
f()#这样才是执行结果,但是有什么意义啊?至少这个例子没啥意义
10
4 偏函数
输出2进制数的值的一个int函数的写法如下:
def int2(x, base=2):
return int(x, base)
#测试下代码
int2('100000')
32
functools.partial就是帮助我们创建一个偏函数的,不需要我们自己定义int2(),可以直接使用下面的代码创建一个新的函数int2:
#偏函数的实现
import functools
int2 = functools.partial(int,base = 2)
int2('10000000')
128