13 python装饰器,函数对象以及一些高阶函数如map/reduce,匿名函数,返回函数,偏函数等等

一 装饰器

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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值