any, all, generator

generator expression (生成式)

  • 生成式列表生成式 语法非常类似, 把列表生产式中的方括号换成圆括号, 就变成了生成式.
  • 列表生产式生成的是一个list对象, 生成式产生的是一个 generator 对象
  • 任何需要一个可以遍历的序列(sequence)的地方, 都可以使用list或者generator

list对象和generator都可用于迭代, 但list对象在迭代之前, 所有元素的值都已经计算好了, 并且保存在内存中, 但时generator对象的元素在需要获取时才会进行计算, 尚未迭代到的元素还不存在, 因此不占用内存. generator对象保存了当前迭代的位置和生成下一个元素的方法, 这种方式被称为 懒惰计算

In [6]:
g = ( x**2 for x in range(10) )  # 生成一个 generator 对象
print(g)
print( list( g ) )  # 使用list()函数, 获取generator的所有元素
print( list( g ) )  # generator是一次性的, 遍历完后, 将不会重新生成序列, 所里这里得到了一个空列表
<generator object <genexpr> at 0x0000000004E00DE0>
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
[]
In [7]:
# generator与其他接受可变参数的函数结合

#这里生产式表达式作为了max()函数的参数, 没有用额外的圆括号, 但单独使用时, 圆括号是必须的
print( max( x**2 for x in range(5) ) )   
print( min( x**2 for x in range(5) ) )
print( sum( x**2 for x in range(5) ) )
16
0
30

generator function (生成函数)

调用生成函数的时候返回的是一个generator, 而不是直接返回其值

In [1]:
def fib(n):
    i,a,b = 0,0,1
    while i < n:
        yield b
        a, b = b, a+b
        i += 1

g = fib(5)  # g是一个generator,而不是斐波那契序列中第六个元素的值
for f in g:
    print(f)
1
1
2
3
5

利用generator function 可以实现非常复杂的生成器, 例如下面这个生成函数每次返回杨辉三角的下一行元素

In [6]:
def triangles(n):
    k, t = 0, [1]
    while k < n:
        yield t
        t = [1] + [ t[i-1] + t[i] for i in range(1, len(t)) ]  +  [1]
        k += 1

tr = triangles(10)
for t in tr:
    print(t)
[1]
[1, 1]
[1, 2, 1]
[1, 3, 3, 1]
[1, 4, 6, 4, 1]
[1, 5, 10, 10, 5, 1]
[1, 6, 15, 20, 15, 6, 1]
[1, 7, 21, 35, 35, 21, 7, 1]
[1, 8, 28, 56, 70, 56, 28, 8, 1]
[1, 9, 36, 84, 126, 126, 84, 36, 9, 1]

any

  • any(seq) 函数以一个布尔序列作为参数, 只要序列中有一个值为True, 则any() 返回True, 否则返回False
  • any 与 generator结合时, 当计算得到一个值为True的元素后, 就直接返回True而不需要继续计算后续的值,因而效率比同样的序列用list表示时高, 这有点像短路或运算, 一旦能确定整个表达式的值, 就不评估后续的值.
In [17]:
print( any( [0, 0, 0 ] ) )     # any() 与list一起使用 , 0 等于`False`
print( any( (0, 0, 0) ) )    # any() 与tuple一起使用  
print( any( [0, 0, 1] ) )     # 1 等于 True

# any() 与 generator结合使用
g = ( char == 't' for char in 'generator') 
print( any( g ) )    # any() 与generator一起使用, 省去了 generator expression的圆括号
print('(g中倒数第三个元素的值是True, 后面应该还有两个`False`)')
for char in g : print( char )
False
False
True
True
(g中倒数第三个元素的值是True, 后面应该还有两个False)
False
False

all

all(seq) 函数以一个布尔序列作为参数, 只要序列中有一个值为False, 则all()返回False,仅当序列的值
全为 True 时, all()才返回True. 与短路与运算类似, 当遇到一个False值时, 就可以直接返回False
同样的原因, all()与generator结合使用时, 效率比与list结合使用时高.

In [19]:
t = [1,1,1,'0' ] # '0' 被视为 True
print( all(t) )

# 与generator结合使用
g = (x for x in range(-5, 6))
print( all( g ) )
# 由于0被视为False, 因此当计算得到0后, all()就直接返回False了, g中后续的元素还没有取出
for x in g : print(x) # 打印出 g 中后续的元素
True
False
1
2
3
4
5