递归函数
使用递归函数的优点是逻辑简单清晰,缺点是过深的调用会导致栈溢出。
针对尾递归优化的语言可以通过尾递归防止栈溢出。尾递归事实上和循环是等价的,没有循环语句的编程语言只能通过尾递归实现循环。
python解释器没有针对尾递归做优化,任何递归函数都存在栈溢出的问题。
普通递归函数:
def fact(n):
if n == 1:
return 1
return n * fact(n-1)
尾递归:
def fact(n):
return fact_iter(n, 1)
def fact_iter(num, product):
if num == 1:
return product
return fact_iter(num-1, num * product)
尾递归调用时,如果做了优化,栈不会增长,因此,无论多少次调用也不会导致栈溢出。
遗憾的是,大多数的编程语言都没有针对尾递归做优化,python解释器也没有做优化,所以,即使把上面的fact(n)函数改成尾递归方式,也会导致栈溢出。
高阶函数
函数本身也可以赋值给变量,即:变量可以指向函数。相当于给函数区别名。
如:a=abs
a(-10)和abs(-10)是一样的效果。
函数名其实就是指向函数的变量。所以可以让函数名指向别的数据。
如:abs = 10 #将函数名abs指向了整数10,此时调用abs(-10)就会报错,因为abs不再指向绝对值函数了。
既然变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数。
编写高阶函数,就是让函数的参数能够接收别的函数。
如:def add(x, y, func):
return func(x) + func(y)
调用:add(-4 , 6, abs) #10
map(f, iterable):
map函数接收两个参数,一个是函数,另一个是Iterable,map将传入的函数依次作用于序列的每个函数,并把结果作为新的Iterator返回。
map()传入的第一个参数是f,即函数对象本身。由于结果r是一个Iterator,Iterator是惰性序列,因此可以通过list()函数让它把整个序列都计算出来并返回一个list。
如: list(map(str, [1, 2, 3, 4, 5, 6, 7, 8, 9, 0])) #将list中所有数字转化为字符:['1','2','3','4','5','6','7','8','9','0']
reduce():
reduce()函数把一个函数作用于一个序列[x1, x2, x3, x4,....]上,这个函数必须接受两个参数,reduce把结果继续和序列的下一个元素做累积计算。
效果就是:reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
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))
或者:
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(lamdba x, y:x*10+y, map(char2num, s))
filter():
和map()类似,filter()用于过滤序列,也是接收一个函数和一个序列。和map()不同的是,filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素。
filter()是一个高阶函数,关键在于正确实现一个筛选函数。filter()函数返回的是一个Iterator,也就是一个惰性序列,所以要强迫filter()完成计算结果,需要用list()函数获得所有结果并返回list。
filter()的作用是从一个序列中筛出符合条件的元素,由于filter()使用了惰性计算,所以只有在取filter()结果的时候,才会真正筛选并每次返回下一个筛出的元素。
例子:获取素数
def _odd_iter():
n = 1
while True:
n = n + 2
yield n
def _not_divisible(n):
return lambda x:x % n > 0
def primes():
yield 2
it = _odd_iter()
while True:
n = next(it)
yield n
it = filter(_not_divisible(n), it)
primes()也是一个无限序列,所以调用时需要设置一个退出循环的条件。
sorted():
sorted()也是一个高阶函数,可以接受一个list,还可以接收一个key函数来实现自定义的排序。
key指定的函数将作用于list的每一个元素上,并根据key函数返回的结果进行排序。
当对字符串排序时,可以将key=str.lower()忽略大小写。要进行反向排序时,不必改动key函数,可以传入第三个参数reverse = True。
返回函数
高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回。
返回闭包时牢记一点:返回函数不要引用任何循环变量,或者后续会发生变化的变量。
匿名函数
关键字lambda表示匿名函数,冒号前面的x表示函数参数。
匿名函数有一个限制,就是只能有一个表达式,不用写return,返回值就是该表达式的结果。
用匿名函数有个好处,因为函数没有名字,不必担心函数名冲突。此外,匿名函数也是一个函数对象,也可以把匿名函数赋值给一个变量,再利用变量来调用该函数。
同样,也可以把匿名函数作为返回值返回。
如:f = lambda x:x*x
def build(x, y):
return lambda: x *x +y * y
python对匿名函数支持有限,只有一些简单的情况下可以使用匿名函数。
偏函数
functools.partial用于创建一个偏函数。functools.partial的作用就是把一个函数的某些参数给固定住(也就是设置默认值),返回一个新的函数,调用这个新函数就会更简单。
创建偏函数时,实际上可以接收函数对象、*args和**kw这3个参数。
如:import functools
int2 = functools.partial(int, base = 2)