递归
def fact(n)
if n == 1:
return 1
return n * fact(n - 1)
- 步骤:确定递归公式、确定边界条件;递归算法解题简洁,但过深的调用会导致栈溢出。
- 计算机中,函数调用时通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,就会导致栈溢出(stock overflow)—解决方法:尾递归:在函数返回时,调用自身,且return语句中不能包含表达式
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) #尾递归中不能包含表达式
- 汉诺塔的实现
#汉诺塔的实现:每次如何就是把n-1个盘子,挪到指定的塔上,然后把最下面最大的盘子移到指定的柱子上。
def move(n, a, b, c):
if n == 1:
print(a, '-->', c)
return
#如何用程序实现汉诺塔
n = n - 1
move(n, a, c, b)
print(a, '-->',c )
move(n, b, a, c)
高级特性–去繁就简
切片(slice)
L = list(range(101))
L[20:-4] #左在右不在
L[:10]
L[80:]
L[:] #复制一个list
L[:10:2]
L[::3]
- 左在右不在:分片需要两个索引作为边界,第一个索引的元素包含在分片内,第二个不包含在分片内();
- 捷径:如果分片要包含序列开始、结尾的元素: numbers[:3] 、numbers[-3:]、numbers[:]空出开始、最后一个索引
- 步长:numbers[1:8:2]、numbers[6:3:-2]。步长为负数,则会从序列的尾部开始向左提取元素;步长为正数,从序列的头部开始向右提取元素;依然遵循左在右不在的原则
迭代(iteration)
- 判断是否可迭代—通过collections模块的iterable类型判断
from collections import Iterable
isinstance('abc', Iterable)
- 2.
#dict的iteration:
d = {'a': 1, 'b': 2, 'c': 3}
for key in d: #only iteration key
print(key)
for value in d.values(): #iteration value
print(value)
for k, v in d.items(): #iteration key and value
print(k,v)
#字符串也是可迭代对象
for ch in 'ABC':
print(ch)
- 对list实现下标循环,使用内置的enumerate函数可以把一个list变成索引-元素对,这样就可以在for循环中同时迭代索引和元素本身
for i, value in enumerate(['a', 'b', 'c']):
print(i, value)
列表生成式(List Comprehensions)-用来创建list
- for循环后面还可加上if判断,可以更精确地筛选内容
[x * x for x in range(1, 11) if x % 2 == 0]
[4, 16, 36, 64, 100] #结果
- 使用两层循环,可以生成全排列
[m + n for m in 'ABC' for n in 'XYZ']
['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ'] #结果
- for循环可以同时使用两个或多个变量(dict.items() 会有key、value),也可以使用两个变量来生成list
- 把一个list中所有的字符串变成小写,通过lower()方法;非字符串类型没有该方法,可以用if筛选出来
L = ['Hello', 'World', 'IBM', 'Apple']
[s.lower() for s in L]
['hello', 'world', 'ibm', 'apple']
生成器(generator)–边循环,边计算
- 解决列表元素太多,占用太多空间问题—生成器中的列表元素可以按照某种算法推算出来,在循环的过程中不断推算后续的元素,用for循环迭generator(可迭代对象)
g = ( x * x for x in range(10)) #创建一个generator
for n in g:
print(n)
- 创建generator方法:把列表生成式中的[]改成();把函数变成generator,含yield 关键字—-函数和generator的区别:函数是顺序执行,遇到return语句或者最后一行函数语句就返回,直接返回结果;而
- generator工作原理:在for循环的过程中不断计算出下一个元素,遇到yield语句就中断并返回,再次执行时从上次返回的yield语句处继续执行,遇到return语句或者执行到函数体最后一行语句,generator结束,for循环随之结束。普通函数调用直接返回结果,而generator函数调用实际返回一个generator对象。
用for循环调用generator,拿不到generator的return语句的返回值,因为fib(6)中,只包含yield返回的语句。如果想要拿到,必须捕获StopIteration错误
def fib(max):
n, a, b = 0, 0, 1
while n < max:
yield b #原来的函数:print b ---这样就定义了一个generator
a, b = b, a + b
n = n + 1
return 'done'
for n in fib(6):
print(n)
#通过捕捉错误读取return中的值
g = fib(6)
while True:
try:
x = next(g)
print('g:', x)
except StopIteration as e:
print('Generator return value:', e.value)
break
迭代器(Iterator)
- 可迭代对象(Iterable可作用于for循环的数据类型):一类是集合数据类型,如list、tuple、dict、set、str等;一类是generator,包括生成器和待yield的generator function。用isinstance(xxx, Iterable) 判断一个对象是否为Iterable对象。
- 迭代器(Iterator, 可被next() 函数调用,并不断返回下一个值的对象):generator都是Iterator对象,但list、tuple、dict虽然是Iterable,但不是Iterator ,可通过iter()函数来转换
- Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。