函数式编程
高阶函数
求绝对值的函数abs()。
abs(-10)
是函数调用,abs
是函数本身。
abs(-10)
10
abs
<built-in function abs>
1.函数本身也可以赋值给变量,即:变量可以指向函数。
2.函数名也是变量。
3.一个最简单的高阶函数:
def add(x, y, f):
return f(x) + f(y)
map/reduce
1.map()
函数接收两个参数,一个是函数,一个是Iterable。
map
将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator
返回。
list(map(str, [1, 2, 3, 4]))
['1', '2', '3', '4']
2.reduce
把一个函数作用在一个序列[x1, x2, x3, ...]
上,这个函数必须接收两个参数,reduce
把结果继续和序列的下一个元素做累积计算。
reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
求和运算可直接用Python内建函数sum()。
filter
Python内建的filter()
函数用于过滤序列(“筛选”函数),接收一个函数和一个序列,把传入的函数依次作用于每个元素,然后根据返回值是True
还是False
决定保留还是丢弃该元素。
def is_odd(n):
return n % 2 == 1
list(filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15]))
# 结果: [1, 5, 9, 15]
在一个list中,删掉偶数,只保留奇数:用filter求素数
①列出从2
开始的所有自然数,构造一个序列:
2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ...
②取序列的第一个数2
,它一定是素数,然后用2
把序列的2
的倍数筛掉:
3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ...
③取新序列的第一个数3
,它一定是素数,然后用3
把序列的3
的倍数筛掉:
5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ...
④取新序列的第一个数5
,然后用5
把序列的5
的倍数筛掉:
7, 8, 9, 10, 11, 12, 13, 14, 15 ...
⑤以此类推,就可以得到所有的素数。
sorted
排序算法
1.Python内置的sorted()
函数就可以对list进行排序。
sorted([36, 5, -12, 9, -21])
[-21, -12, 5, 9, 36]
2.还可接收一个key
函数实现自定义的排序。
sorted([36, 5, -12, 9, -21], key=abs)
[5, 9, -12, -21, 36]
3.要进行反向排序,不必改动key函数,可以传入第三个参数reverse=True。
sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower, reverse=True)
['Zoo', 'Credit', 'bob', 'about']
返回函数
1.返回闭包时,返回函数不要引用任何循环变量,或者后续会发生变化的变量。
2.使用闭包时,对外层变量赋值前,需要先使用nonlocal声明该变量不是当前函数的局部变量。
匿名函数
map()
函数为例:
定义一个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: x * x
就是:
def f(x):
return x * x
匿名函数只能有一个表达式,不用写return
,返回值就是该表达式的结果。
装饰器
1.函数对象有一个__name__
属性(注意:是前后各两个下划线),可以拿到函数的名字。
now.__name__
'now'
f.__name__
'now'
2.log()
是一个decorator,返回一个函数。即在log()
函数中返回的wrapper()
函数。
wrapper()
函数的参数定义是(*args, **kw)
,因此,wrapper()
函数可以接受任意参数的调用。
3.不需要编写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
或者针对带参数的decorator:
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
import functools
是导入functools
模块。需记住在定义wrapper()
的前面加上@functools.wraps(func)
即可。
偏函数
1.int()
函数还提供额外的base
参数,默认值为10
。如果传入base
参数,就可以做N进制的转换。
int('12345', base=8)
5349
int('12345', 16)
74565
eg:①可以定义一个int2()
的函数,默认把base=2
传进去:
def int2(x, base=2):
return int(x, base)
②functools.partial
是帮助我们创建一个偏函数的,不需要我们自己定义int2():
import functools
int2 = functools.partial(int, base=2)
int2('1000000')
64
int2('1010101')
85
functools.partial
的作用:把一个函数的某些参数给固定住(也就是设置默认值),返回一个新的函数,调用这个新函数会更简单。
模块
1.一个.py文件就称之为一个模块(Module)。遵循Python变量命名规范,不要使用中文、特殊字符。
2.每一个包目录下面都会有一个__init__.py
的文件,是必须存在的。否则,Python就把这个目录当成普通目录,而不是一个包。__init__.py
可以是空文件,也可以有Python代码,因为__init__.py
本身就是一个模块,而它的模块名就是mycompany
。
自己创建模块时要注意命名,不能和Python自带的模块名称冲突。例如,系统自带了sys模块,自己的模块就不可命名为sys.py,否则将无法导入系统自带的sys模块。
使用模块
1.正常的函数和变量名是公开的(public),可以被直接引用,比如:abc
,x123
,PI
等。
2.__xxx__
这样的变量是特殊变量,可以被直接引用,但是有特殊用途,比如__author__
,__name__
就是特殊变量,我们自己的变量一般不要用这种变量名。
3._xxx
和__xxx
这样的函数或变量就是非公开的(private),不应该被直接引用,比如_abc
,__abc
等。
外部不需要引用的函数全部定义成private,只有外部需要引用的函数才定义为public。
安装第三方模块
要添加自己的搜索目录,有两种方法:
1.直接修改sys.path
,添加要搜索的目录:(在运行时修改,运行结束后失效)。
import sys
sys.path.append('/Users/michael/my_py_scripts')
2.设置环境变量PYTHONPATH
,该环境变量的内容会被自动添加到模块搜索路径中。设置方式与设置Path环境变量类似。注意只需要添加你自己的搜索路径,Python自己本身的搜索路径不受影响。