Python学习目录python
练习代码git
函数式编程就是一种抽象程度很高的编程范式,纯粹的函数式编程语言编写的函数没有变量,所以,任意一个函数,只要输入是肯定的,输出就是肯定的,这种纯函数咱们称之为没有反作用。而容许使用变量的程序设计语言,因为函数内部的变量状态不肯定,一样的输入,可能获得不一样的输出,所以,这种函数是有反作用的。函数式编程的一个特色就是,容许把函数自己做为参数传入另外一个函数,还容许返回一个函数!github
Python对函数式编程提供部分支持。因为Python容许使用变量,所以,Python不是纯函数式编程语言。编程
函数是Python内建支持的一种封装,咱们经过把大段代码拆成函数,经过一层一层的函数调用,就能够把复杂任务分解成简单的任务,这种分解能够称之为面向过程的程序设计。函数就是面向过程的程序设计的基本单元。网络
而函数式编程(请注意多了一个“式”字)——Functional Programming,虽然也能够归结到面向过程的程序设计,但其思想更接近数学计算。闭包
咱们首先要搞明白计算机(Computer)和计算(Compute)的概念。在计算机的层次上,CPU执行的是加减乘除的指令代码,以及各类条件判断和跳转指令,因此,汇编语言是最贴近计算机的语言。而计算则指数学意义上的计算,越是抽象的计算,离计算机硬件越远。对应到编程语言,就是越低级的语言,越贴近计算机,抽象程度低,执行效率高,好比C语言;越高级的语言,越贴近计算,抽象程度高,执行效率低,好比Lisp语言。app
在python中函数名是指向函数的变量,当函数的参数也是函数的时候,这种函数咱们称之为高阶函数。编程语言
def add(x, y, f):
return f(x) + f(y)
add(1, -6, abs)
复制代码
map()函数接收两个参数,一个是函数,一个是Iterable,map将传入的函数依次做用到序列的每一个元素,并把结果做为新的Iterator返回。函数式编程
def f(x):
return x * x
r = map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])
print(list(r))
>>> [1, 4, 9, 16, 25, 36, 49, 64, 81]
复制代码
reduce把一个函数做用在一个序列[x1, x2, x3, ...]上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素作累积计算,效果以下:函数
reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
复制代码
结合map和reduce能够整理出一个str2int的函数:
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 char2num(s):
return DIGITS[s]
def str2int(s):
return reduce(lambda x, y: x * 10 + y, map(char2num, s))
复制代码
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]
复制代码
对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(['bob', 'about', 'Zoo', 'Credit'])
['Credit', 'Zoo', 'about', 'bob']
复制代码
忽略大小写:
>>> 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']
复制代码
高阶函数除了能够接受函数做为参数外,还能够把函数做为结果值返回。
咱们来实现一个可变参数的求和。一般状况下,求和的函数是这样定义的:
def calc_sum(*args):
ax = 0
for n in args:
ax = ax + n
return ax
复制代码
可是,若是不须要马上求和,而是在后面的代码中,根据须要再计算怎么办?能够不返回求和的结果,而是返回求和的函数:
def lazy_sum(*args):
def sum():
ax = 0
for n in args:
ax = ax + n
return ax
return sum
复制代码
当咱们调用lazy_sum()
时,返回的并非求和结果,而是求和函数:
>>> f = lazy_sum(1, 3, 5, 7, 9)
>>> f
<function lazy_sum.<locals>.sum at 0x101c6ed90>
复制代码
调用函数f
时,才真正计算求和的结果
>>> f()
25
复制代码
如上所示的例子中,咱们在函数
lazy_sum
中又定义了函数sum
,而且,内部函数sum
能够引用外部函数lazy_sum
的参数和局部变量,当lazy_sum
返回函数sum
时,相关参数和变量都保存在返回的函数中,这种称为“闭包(Closure)”。
注意点:返回函数不要引用任何循环变量,或者后续会发生变化的变量。
以下所示:
def count():
fs = []
for i in range(1, 4):
def f():
return i*i
fs.append(f)
return fs
f1, f2, f3 = count()
复制代码
返回结果以下:
>>> f1()
9
>>> f2()
9
>>> f3()
9
复制代码
关键字
lambda
表示匿名函数,冒号前面的x
表示函数参数。匿名函数有个限制,就是只能有一个表达式,不用写return
,返回值就是该表达式的结果。
>>> list(map(lambda x: x * x, [1, 2, 3, 4, 5, 6, 7, 8, 9]))
[1, 4, 9, 16, 25, 36, 49, 64, 81]
复制代码
代码运行期间动态增长功能的方式,称之为“装饰器”(Decorator)。本质上,decorator就是一个返回函数的高阶函数。
定义一个能打印日志的decorator,能够定义以下:
def log(func):
def wrapper(*args, **kw):
print('call %s():' % func.__name__)
return func(*args, **kw)
return wrapper
复制代码
观察上面的log
,由于它是一个decorator,因此接受一个函数做为参数,并返回一个函数。咱们要借助Python的@语法,把decorator置于函数的定义处:
@log
def now():
print('2015-3-25')
>>> now()
call now():
2015-3-25
复制代码
把@log
放到now()
函数的定义处,至关于执行了语句:now = log(now)
,now
变量指向了新的函数。
若是decorator自己须要传入参数,那就须要编写一个返回decorator的高阶函数,写出来会更复杂。好比,要自定义log的文本:
def log(text):
def decorator(func):
def wrapper(*args, **kw):
print('%s %s():' % (text, func.__name__))
return func(*args, **kw)
return wrapper
return decorator
复制代码
这个3层嵌套的decorator用法以下:
@log('execute')
def now():
print('2015-3-25')
>>> now()
execute now():
2015-3-25
复制代码
和两层嵌套的decorator相比,3层嵌套的效果是这样的:>>> now = log('execute')(now)
有个问题,通过decorator装饰以后的函数,它们的__name__
已经从原来的'now'
变成了'wrapper'
:
>>> now.__name__
'wrapper'
复制代码
Python内置的functools.wraps
用来复制函数_name_属性的:
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
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
复制代码
Python的
functools
模块提供了不少有用的功能,其中一个就是偏函数(Partial function)。把一个函数的某些参数给固定住(也就是设置默认值),返回一个新的函数,调用这个新函数会更简单。建立偏函数时,实际上能够接收函数对象、
*args
和**kw
这3个参数。
好比要使用int()
函数去转换二进制字符串,本来的写法是:int(x, base=2)
,若是量大的话,很麻烦,因此咱们能够这么写:
>>> import functools
>>> int2 = functools.partial(int, base=2)
>>> int2('1000000')
64
>>> int2('1010101')
85
复制代码
上面的in2 = functools.partial(int, base=2)
至关于:
kw = { 'base': 2 }
int('10010', **kw)
复制代码