当前位置:   article > 正文

Python中的列表生成式(List Comprehensions)和列表生成器(Generator)_python 列表生成式

python 列表生成式

Python中的列表生成式(List Comprehensions)和列表生成器(Generator),是Python提供的两个高级应用机制。

生成式是一种简写机制,坚持了龟叔的“Python要简单优雅”的设计理念。

生成器虽然翻译成中文以后只有一字之差,但是实现的机制和生成式已经完全不同了。它存储的是一个算法,而非具体数据。如何理解呢?听我娓娓道来。

一、列表生成式(List Comprehensions)

列表生成式是Python提供的一种简易的列表生成表达式。对于一些极其规律且简单逻辑的列表生成算法,可以用列表生成式一行搞定。

1.1语法格式:

它的语法格式是:

[列表元素模式(空格)列表元素生成算法(数据来源)表达]

举个例子:

 有如下需求:要生成[1x1, 2x2, 3x3, ..., 10x10]这样的一个list

传统的思路是:

  1. L = []
  2. for x in range(1, 11):
  3. L.append(x * x)
'
运行

接下来是列表生成式写法:

[x * x for x in range(1, 11)]'
运行

是不是简洁了很多?我想,不用我解释,应该也浅显易懂吧。

如果翻译成白话文,上面这条语句的意思是:

生成这样一个列表,他的每一个元素都是x*x,其中,x的值是这样的 for x in range(1, 11)

1.2列表生成式中的循环和选择

列表生成式中的for循环后可加if判断

例如:求偶数平方数列。可以用列表生成式来书写

[x * x for x in range(1, 11) if x % 2 == 0]
'
运行

.例如:生成'ABC‘和'XYZ'的完全结合子串

[m + n for m in 'ABC' for n in 'XYZ']
'
运行

1.3列表生成式的元素模式花式表达

列表生成式也可以使用两个变量来生成list

  1. d = {'x': 'A', 'y': 'B', 'z': 'C' }
  2. [k + '=' + v for k, v in d.items()]
'
运行

.列表中所有字符串变小写

  1. L = ['Hello', 'World', 'IBM', 'Apple']
  2. [s.lower() for s in L]
'
运行

.以及利用if语句是算法更灵活,如下例中,合理屏蔽掉18这个非字符串数据:

  1. L1 = ['Hello', 'World', 18, 'Apple', None]
  2. L2 = [s.lower() for s in L1 if isinstance(s, str) == True]
'
运行

二、生成器Generator

有一句至理名言,必须牢记:

生成器保存的是算法。

2.1生成器的创建

生成器的创建很简单。将列表生成式的[]换成()即可

例如,创建一个能够生成x平方的列表的生成器如下:

g = (x * x for x in range(10))
'
运行

2.2生成器元素的显示:

生成器保存的是生成算法,而非数据本身,因此,它与生成式不同,它并不携带任何数据,因此,想用print的形式是无法输出任何数据的,只能输出一个表示本对象是一个生成器对象的提示。如下:

  1. g = (x * x for x in range(10))
  2. print(g)
  3. 结果为:
  4. <generator object <genexpr> at 0x00000252A2AC1690>

生成器像是一个携带着数据的宝盒,需要一把钥匙触发机关,他才会持续不断的根据算法产生数据并输出。这种触发算法的钥匙最常用的两个是:1.next方法,2.for循环的遍历。

2.2.1next方法

next方法会触发一次算法的计算,一次next就会激发一次算法的计算产生下一个数据。例如:

对于生成器:

g = (x * x for x in range(10))'
运行

如果:

  1. next(g)
  2. next(g)

则会输出:

1

4

两个数据。

2.2.2for循环遍历

使用for循环遍历,可以持续触发算法,并输出所有算法能覆盖的数据

例如:

对于生成器:

g = (x * x for x in range(10))'
运行

如果:

  1. for n in g:
  2. print(n)

则会输出所有的数列元素1,4,9,16等。

2.3生成器的函数实现形式

 当推算算法比较复杂,可以用函数来实现。

Fibonacci数列,很显然,这个算法写不到一行上去。没办法用小括号()的形式来展现算法,可以使用函数的形式来实现生成器。Fibonacci数列的普通函数实现如下:

  1. def fib(max):
  2. n, a, b = 0, 0, 1
  3. while n < max:
  4. print(b)
  5. a, b = b, a + b
  6. n = n + 1
  7. return 'done'
'
运行

这有个小细节,其中的

a,b = b, a + b的意义是,先将右边的值全部算出,再分别赋值给左边的变量。

相当于:

temp1 = b

temp2 = a + b

a = temp1

b = temp2

而不是:

b = a + b

a = b

自己体会一下区别。

2.3.1 yield的用法

上面的Fibonacci数列的普通函数稍加改造,就可以变成一个生成器函数。

关键在于yield关键字。

先上案例程序:

  1. def fib(max):
  2. n, a, b = 0, 0, 1
  3. while n < max:
  4. yield b
  5. a, b = b, a + b
  6. n = n + 1
  7. return 'done'
'
运行

将普通函数中的print语句,换成yield。

如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator。

函数是顺序执行,遇到return或最后一行返回。

包含yield关键字的生成器函数的执行逻辑如下:

Generator每次调用next()时候执行,遇到yield返回。再次执行,从上一次返回的yield处继续执行。

刚刚构建的生成器fib,遇到next调用时,就生成一个fibnacci数列的元素。

  1. g = fib(10)
  2. next(g)
  3. next(g)
  4. next(g)
  5. next(g)

执行结果为:

1

1

2

3

再举一个例子:

写一个generator依次返回数字1,3,5

  1. def odd():
  2. print('step 1')
  3. yield 1
  4. print('step 2')
  5. yield(3)
  6. print('step 3')
  7. yield(5)
'
运行

可以利用next择机输出(或者说延迟输出)想要的数据

  1. o = odd()
  2. next(o)
  3. next(o)
  4. next(o)
  5. 得到的结果为:
  6. step 1
  7. 1
  8. step 2
  9. 3
  10. step 3
  11. 5

如果再使用next(o),则会产生异常。

Traceback (most recent call last):   File "<stdin>", line 1, in <module> StopIteration

2.4生成器Generator的作用

生成器和生成式,好像差不多啊。

生成器函数和普通函数,好像也差不多啊。

2.4.1算法的滞后输出

生成器的最大用途,是可以让算法的输出滞后,在用户需要的时机,缓缓输出。可以通过上面的例子来推敲和理解一下。

2.4.2无限数据的有限表达

生成器让类似于“自然数集”这样的无限数据生成算法,有了有限输出的空间。这一点尤为关键。因为算法必须是有限的,无限的算法是无意义的。毕竟,无论是时间还是空间,都必须是有限的,才能实施下去。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/944222
推荐阅读
相关标签
  

闽ICP备14008679号