列表推导式、集合推导式,字典推导式
生成器表达式、生成器函数
递归函数、斐波那契数列
推导式
Python里面有个很棒的语法糖(syntactic sugar),它就是 list comprehension ,有人把它翻译成“列表推导式”,也有人翻译成“列表解析式”。名字听上去很难理解,但是看它的语法就很清晰了。虽然名字叫做 list comprehension,但是这个语法同样适用于dict、set等这一系列可迭代(iterable)数据结构
列表推导式
- [返回值表达式 for 元素 in 可迭代对象 if 条件]
- 返回一个新的列表
- [返回值表达式 for 元素 in 可迭代对象 if 条件 1 if 条件 2]
- [返回值表达式 for 元素 in 可迭代对象 1 for 元素 in 可迭代对象 2]
[x for x in range(10) if x%2==0]
[x**2 for x in range(20) if x%2==0 if x%3==0] # 等价于[x**2 for x in range(20) if x%2==0 and x%3==0]
[x+y for x in range(4) for y in range(3)]
# 等价于
ret = []
for x in range(4):
for y in range(3):
ret.append(x+y)
集合推导式
- {返回值表达式 for 元素 in 可迭代对象 if 条件}
- 遵循集合元素的条件,如 {[x] for i in range(10)} 则会抛 TyprError 异常
unhashable type:'list'
字典推导式
- {字典返回值表达式 for 元素 in 可迭代对象 if 条件}
- key 值遵循字典 key 条件,如 {str(x):y for x in range(3) for y in range(4)}
生成器
- generator 是生成器对象,可以由生成器表达式得到,也可以使用 yield 关键字得到一个生成器函数,调用这个函数得到一个生成器对象
- 生成器对象是可迭代对象,也是迭代器
- 生成器对象是延迟计算,惰性求值的
生成器表达式
- (返回值表达式 for 元素 in 可迭代对象 if 条件)
g = (i for i in range(1,5))
next(g)
-----------------------------
1
-----------------------------
for i in g:
print(i)
next(g)
-----------------------------
2
3
4
---------------------------------------------------------------------------
StopIteration Traceback (most recent call last)
<ipython-input-44-06a6c21102c8> in <module>()
1 for i in g:
2 print(i)
----> 3 next(g)
StopIteration:
- 跟列表推导式对比:生成器延迟计算,生成器占用内存少,不需要立即占用内存,计算速度快
生成器函数
生成器函数定义
- 函数体内包含
yield
语句的函数
def inc():
for i in range(5):
print('~~~~~~~~~')
yield i
g = inc()
print(type(g))
print(next(g))
--------------------
<class 'generator'>
~~~~~~~~~
0
- 生成器函数调用不会立即执行函数体
- 需要使用
next
函数来驱动生成器函数执行后获得的生成器对象
生成器函数的执行
def gen():
print('line 1')
yield 1
print('line 2')
yield 2
print('line 3')
return 3
yield 4
print(type(gen()))
print(next(gen()))
print(next(gen())) # 重新创建函数对象
g = gen()
print(type(g))
print(next(g))
print(next(g))
# print(next(g)) # StopIteration
print(next(g,'end')) # 没有元素给个默认值
----------------------------------
<class 'generator'>
line 1
1
line 1
1
<class 'generator'>
line 1
1
line 2
2
line 3
end
- 生成器函数可以含多个
yield
return
语句可以终止函数运行,但return
语句的返回值不能被获取到return
会导致当前函数返回,无法继续执行,也无法继续获取下一个值,抛出StopIteration
异常
yield from
- py3.3 新增简化的语法
# yield写法
def inc():
for x in range(1000):
yield x
# 使用yield from 简化
def inc():
yield from range(1000)
生成器交互 (send 方法)
- 认识
send
方法
def counter():
count = 0
while True:
count += 1
response = yield count
print(response,'~~~~~~~~~~~')
c = counter()
next(c) # 1,返回1后暂停
next(c) # None~~~~~~~~~~~ 2 #下次调用,才会拿到response并打印
c.send(0) # 0~~~~~~~~~~~~~ 3
#生成器对象的send方法,将实参0赋值给response并推动生成器启动并执行,完成交互
- 具有重置功能的计数器
def counter():
count = 0
while True:
count += 1
response = yield count
if response is not None:
count = response
c = counter()
print(next(c))
print(next(c))
print('~~~~~~~~~~~~~~~')
c.send(-1) # 重置计数器
print(next(c))
print(next(c))
-------------------------------------
1
2
~~~~~~~~~~~~~~~
1
2
- 改进的具有重置功能的计数器
# 进一步改进
def inc():
def counter():
i = 0
while True:
i += 1
response = yield i
if response is not None:
i = response
c = counter()
def _inc(x=False):
if x:
return c.send(0)
else:
return next(c)
return _inc
# return lambda x=False:c.send(0) if x else next(c) #等价_inc()
foo = inc()
print(foo())
print(foo())
print(foo())
print('~~~~~~~~~~~~~~~~~~')
print(foo(True)) # 设置计数器清零
print(foo()) # 再次调用重新计数
print(foo())
print(foo())
print(foo())
-------------------------------------
1
2
3
~~~~~~~~~~~~~~~~~~
1
2
3
4
- 总结:
- 调用
send
方法,可以把 send 的实参传给yield
语句做结果,这个结果可以在等式右边被赋值给其它变量 send
和next
一样可以推动生成器启动并执行
- 调用
- 函数直接或者间接调用自身
- 递归一定要有边界条件,一定要有退出条件,不然就是无限调用
- 递归深度不宜过深
斐波那契数列
- fibonacci number:
1,1,2,3,5,8...
- 可以理解为
f(0)=0, f(1)=1, f(n)=f(n-1)+f(n-2)
- 参数 n 作为边界条件,用于计数
- 当边界条件不满足时,递归前进,不满足时递归退出
# 实现方法1:
def fib(n):
return 1 if n<3 else fib(n-1) + fib(n-2)
print(fib(5))
-------------------------------------------
5
- for 循环实现
# 实现方法2
def fib(n,a=0,b=1):
for i in range(n-1):
a,b = b,a+b
return b
print(fib(5))
- 递归实现改进
# 实现方法3
def fib(n,a=0,b=1):
a,b = b,a+b
if n == 1:
return a
return fib(n-1,a,b)
print(fib(5))
- 生成器实现
# 实现方法4(推荐)
def fib():
x = 0
y = 1
while True:
yield y
x, y = y, x + y
foo = fib()
for i in range(101):
print(next(foo))
参考
- magedu