您的位置:首页 > 编程语言 > Python开发

Python学习笔记——函数式编程

2016-09-03 17:09 459 查看
下面学习一下Python的函数式编程。

http://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/0014317848428125ae6aa24068b4c50a7e71501ab275d52000

1. 高阶函数

变量可以指向函数。

函数名也是变量。

一个函数可以接收另一个函数作为参数,这种函数称为高阶函数。

2. map/reduce

Python内建了map()和reduce()函数。

map()函数接收两个参数,第一个参数是函数,第二个参数是Iterable。map将传入的函数依次作用在Iterable的每个元素,并把结果作为新的Iterator返回。

Iterator是惰性序列。

例如我们将list的所有数字转为字符串,可以这么写:

list(map(str, [1, 2, 3, 4, 5]))


reduce()函数同样接收两个参数,不过第一个参数的函数要求接收两个参数,reduce把结果继续和下一个元素做累积运算。

也就是说:

reduce(f, [x1, x2, x3]) = f(f(x1, x2), x3)


要使用reduce,需要引入:

from functools import reduce


3. filter

filter()也是接收两个参数,一个函数和一个序列。filter()将函数作用于序列的每个元素,根据返回值是True还是False来决定保留还是丢弃该元素。

filter()返回的也是一个惰性序列,如果要强迫完成计算结果,需要用list()获得所有结果并返回list。

比如输出回文数字的方法:

def is_palindrome(n):
return n == int(str(n)[::-1])

output = filter(is_palindrome, range(1, 1000))
print(list(output))

# [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 22, 33, 44, 55, 66, 77, 88, 99, 101, 111, 121, 131, 141, 151, 161, 171, 181, 191, 202, 212, 222, 232, 242, 252, 262, 272, 282, 292, 303, 313, 323, 333, 343, 353, 363, 373, 383, 393, 404, 414, 424, 434, 444, 454, 464, 474, 484, 494, 505, 515, 525, 535, 545, 555, 565, 575, 585, 595, 606, 616, 626, 636, 646, 656, 666, 676, 686, 696, 707, 717, 727, 737, 747, 757, 767, 777, 787, 797, 808, 818, 828, 838, 848, 858, 868, 878, 888, 898, 909, 919, 929, 939, 949, 959, 969, 979, 989, 999]


4. sorted

Python内置的sorted()可以对list进行排序。

可以接收一个key函数来支持自定义的排序规则。

若需要进行反向排序,可传入参数reverse=True。

比如将字符串倒序排序,且忽略大小写,可以这么写:

sorted(['a', 'B', 'c'], key=str.lower, reverse=True)


5. 返回函数

一个函数可以返回一个函数最为结果,当返回函数时,该函数并未执行。

返回函数中不要引用任何可能变化的变量,否则可能会拿到意想不到的结果。

比如这段程序:

def calc():
rs = []
for i in range(1, 4):
def f():
return i * i
rs.append(f)
return rs

f1, f2, f3 = calc()
f1()
# 9
f2()
# 9
f3()
# 9
本来预想应该是1,4,9,可实际上却是3个9。原因就在于返回的函数并不是直接执行,而是在调用时才执行。

但是在调用时,由于已遍历生成了数组,i已经是3了,所以这三个函数执行的结果就都是9了。

6. 匿名函数

有些时候,我们不需要显示的定义函数,这时候就可以使用匿名函数。

关键字lambda表示匿名函数,冒号前面的是参数。

匿名函数有一个限制:只能有一个表达式,返回值就是该表达式的结果。

匿名函数也是一个函数对象,可以赋值给一个变量,或者作为函数的返回值。

7. 装饰器

假设我们想在一个函数调用前后打印一些日志,又不希望修改函数本身的定义,就可以使用“装饰器”模式来增强函数的功能。

本质上,装饰器就是一个返回函数的高阶函数,可以这么定义:

import functools

def log(func):
@functools.wraps(func)
def wrapper(*args, **kw):
print("call %s():" % func.__name__)
return func(*args, **kw)
return wrapper
函数对象有一个__name__属性,可以拿到函数的名字。另外为了使拿到的名字是实际的名字,而不是wrapper的名字,可以使用functools的wraps方法。

如果是带参数的修饰器,可以这么定义:

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
def now():
print('2016')

@log('execute')
def now():
print('2016')

8. 偏函数

functools.partial可以帮助创建偏函数,即把一个函数的某些参数给固定住,返回一个新的函数。

创建偏函数时,可以接收函数对象、*args、**kw这3个参数。

当传入

int2 = functools.partial(int, base=2)
实际上固定了int()函数的关键字参数base,也就是:

int2('1010')

相当于:

kw = {'base': 2}
int2('1010', **kw)
当传入:

max2 = functools.partial(max, 10)
实际上会把10当做*args的一部分自动加到左边,也就是:

max2(5, 6, 7)
相当于:

args = (10, 5, 6, 7)
max(*args)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  python