Python匿名函数

Posted by Csming on 2017-04-16

匿名函数

不显式定义的函数

eg:

1
2
3
4
5
6
lambda x: x * x

# 相当于:

def f(x):
return x * x

实例:

1
2
list(map(lambda x: x * x, [1, 2, 3, 4, 5, 6, 7, 8, 9]))
# [1, 4, 9, 16, 25, 36, 49, 64, 81]

匿名函数只能有一个表达式,不用写return;表达式的结果就是返回值;

eg:

1
2
3
4
5
f = lambda x: x * x

f(5)

# 25

也可以把匿名函数作为返回值返回

1
2
def build(x, y):
return lambda: x * x + y * y

装饰器

  • 函数对象有一个__name__属性,可以获取函数的名字
1
2
3
4
5
def now():
print("3017-4-16")

now.__name__
# now
  • decorator 是一个返回函数的高阶函数;
    要增强now()函数的功能,比如,在函数调用前后自动打印日志等;但不希望修改now()函数的定义,这种代码运行期间动态增加功能的方式,就称为装饰器(decorator);

eg:

1
2
3
4
5
def log(func):
def wrapper(*args, **kw):
print('call %s():' % func.__name__)
return func(*args, **kw)
return wrapper

借助Python的@语法,把decorator置于函数的定义处
然后调用函数时,还会在运行now()函数前打印一行日志
eg:

1
2
3
4
5
6
7
8
@log
def now():
print("3017-4-16")

now()

# call now()
# 3017-4-16

@log 相当于执行了:now = log(now)

log()就是一个decorator,返回一个函数;所以原来的now()函数仍然存在,智慧现在同名的now变量指向了新的函数;于是调用now()将执行新函数;即,log()函数中返回的wrapper函数;(好像明白了什么,这算是拓展功能之类的吗)

如果decorator本身需要传入参数,那么编写一个返回decorator的高阶函数
eg:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def log(text):
def decorator(func):
def wrapper(*args, **kw):
print('%s %s():' % (text, func.__name__))
return func(*args, **kw)
return wrapper
retrun decorator

@log('execute')
def now():
print("3017-4-16")
# now()
# execute now():
# 3017-4-16

相当于:now = log(‘execute’)(now)

以上两种decorator的定义都没有问题,但还差最后一步。因为我们讲了函数也是对象,它有__name__等属性,但你去看经过decorator装饰之后的函数,它们的__name__已经从原来的’now’变成了’wrapper’
不需要编写wrapper.name = func.__name__这样的代码,Python内置的functools.wraps就是干这个事的

1
2
3
4
5
6
7
8
import functools

def log(func):
@functools.wraps(func)
def wrapper(*args, **kw):
print('call %s():' % func.__name__)
return func(*args, **kw)
return wrapper

import functools是导入functools模块

偏函数

如果有一个函数:func(xx ,xxx);要传入两个参数;如果,我们想要调用之传入一个参数的该函数,可以声明一个新函数;eg:

1
2
3
4
def int2(x, base=2):
return int(x, base)

int2(x)

functools.partial可以帮助我们创建这样的偏函数;不需要我们自己定义int2();
eg:

1
2
int2 = functools.partial(int, base=2)
int2('100000')

新的int2函数,仅仅是把base参数重新设定默认值为2,但也可以在函数调用时传入其他值

1
2
int2('1000000', base=10)
# 1000000

参考资料:http://www.liaoxuefeng.com/