列表推导式、集合推导式,字典推导式
生成器表达式、生成器函数
递归函数、斐波那契数列

推导式


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
  • 总结:
    1. 调用send方法,可以把 send 的实参传给yield语句做结果,这个结果可以在等式右边被赋值给其它变量
    2. sendnext一样可以推动生成器启动并执行
  • 函数直接或者间接调用自身
  • 递归一定要有边界条件,一定要有退出条件,不然就是无限调用
  • 递归深度不宜过深

斐波那契数列

  • fibonacci number1,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