1、函数式编程
1.1 高阶函数
把函数作为参数传入,这样的函数称为高阶函数,函数式编程就是指这种高度抽象的编程范式
函数名也是变量,函数名其实就是指向函数的变量!对于abs()
这个函数,完全可以把函数名abs
看成变量,它指向一个可以计算绝对值的函数
1.2 map/reduce
1.2.1 map()函数接收两个参数,一个是函数,一个是Iterable,map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回
>>> def f(x): return x * x >>> r = map(f,[1,2,3,4,5,6,7,8,9]) >>> list(r) [1, 4, 9, 16, 25, 36, 49, 64, 81]
1.2.2 reduce把一个函数作用在一个序列[x1, x2, x3, ...]上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算,其效果就是:
reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
利用reduce把序列[1, 3, 5, 7, 9]变换成整数13579
>>> from functools import reduce >>> def fn(x, y): ... return x * 10 + y ... >>> reduce(fn, [1, 3, 5, 7, 9]) 13579
配合map(),把str转换为int的函数
from functools import reduce
DIGITS = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}
def str2int(s):
def fn(x, y):
return x * 10 + y
def char2num(s):
return DIGITS[s]
return reduce(fn, map(char2num, s))
1.2.3 filter
Python内建的filter()函数用于过滤序列
和map()类似,filter()也接收一个函数和一个序列。和map()不同的是,filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素。
例如,在一个list中,删掉偶数,只保留奇数,可以这么写
>>> def is_odd(n): return n%2 == 1 >>> list(filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15])) [1, 5, 9, 15]
filter()函数返回的是一个Iterator,也就是一个惰性序列,所以要强迫filter()完成计算结果,需要用list()函数获得所有结果并返回list
1.2.4 sorted
Python内置的sorted()函数就可以对list进行排序
>>> sorted([36, 5, -12, 9, -21]) [-21, -12, 5, 9, 36]
sorted()函数也是一个高阶函数,它还可以接收一个key函数来实现自定义的排序,例如按绝对值大小排序
>>> sorted([36, 5, -12, 9, -21], key=abs) [5, 9, -12, -21, 36]
对字符串排序,我们给sorted传入key函数,即可实现忽略大小写的排序
>>> sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower) ['about', 'bob', 'Credit', 'Zoo']
要进行反向排序,不必改动key函数,可以传入第三个参数reverse=True
>>> sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower, reverse=True) ['Zoo', 'Credit', 'bob', 'about']
1.3 匿名函数
当我们在传入函数时,有些时候,不需要显式地定义函数,直接传入匿名函数更方便
以map()函数为例,计算f(x)=x2时,除了定义一个f(x)的函数外,还可以直接传入匿名函数
>>> list(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表示函数参数
匿名函数有个限制,就是只能有一个表达式,不用写return,返回值就是该表达式的结果
匿名函数也是一个函数对象,也可以把匿名函数赋值给一个变量,再利用变量来调用该函数
>>> f = lambda x: x * x >>> f(5) 25
可以把匿名函数作为返回值返回
def build(x, y): return lambda: x * x + y * y
1.4 偏函数
在介绍函数参数的时候,通过设定参数的默认值,可以降低函数调用的难度。而偏函数也可以做到这一点
int()函数还提供额外的base参数,默认值为10。如果传入base参数,就可以做N进制的转换
>>> int('12345', base=8) 5349 >>> int('12345', 16) 74565
functools.partial就是帮助我们创建一个偏函数的,不需要我们自己定义int2(),可以直接使用下面的代码创建一个新的函数int2
>>> import functools >>> int2 = functools.partial(int, base=2) >>> int2('1000000') 64 >>> int2('1010101') 85
2、模块
为了编写可维护的代码,我们把很多函数分组,分别放到不同的文件里,这样,每个文件包含的代码就相对较少,很多编程语言都采用这种组织代码的方式。在Python中,一个.py文件就称之为一个模块(Module)
2.1 __init__
每一个包目录下面都会有一个__init__.py的文件,这个文件是必须存在的,否则,Python就把这个目录当成普通目录,而不是一个包。__init__.py可以是空文件,也可以有Python代码,因为__init__.py本身就是一个模块,而它的模块名就是mycompany
2.2 模块:
模块是一组Python代码的集合,可以使用其他模块,也可以被其他模块使用。
创建自己的模块时,要注意:
1.模块名要遵循Python变量命名规范,不要使用中文、特殊字符;
2.模块名不要和系统模块名冲突,最好先查看系统是否已存在该模块,检查方法是在Python交互环境执行import abc,若成功则说明系统存在此模块。
2.3 关于if __name__ == '__main__'的解释
1:__name__是一个变量。前后加了双下划线是因为这是系统定义的名字。普通变量不要使用此方式命名变量。
2:Python有很多模块,而这些模块是可以独立运行的!这点不像C++和C的头文件。
3:import的时候是要执行所import的模块的。
4:__name__就是标识模块的名字的一个系统变量。这里分两种情况:假如当前模块是主模块(也就是调用其他模块的模块),那么此模块名字就是__main__,通过if判断这样就可以执行“__mian__:”后面的主函数内容;假如此模块是被import的,则此模块名字为文件名字(不加后面的.py),通过if判断这样就会跳过“__mian__:”后面的内容。
通过上面方式,python就可以分清楚哪些是主函数,进入主函数执行;并且可以调用其他模块的各个函数等等。