前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >python套路-高级特性之生成器

python套路-高级特性之生成器

作者头像
efonfighting
发布2020-05-16 13:42:41
4240
发布2020-05-16 13:42:41
举报
文章被收录于专栏:一番码客一番码客

先看几个例子。

例子一:生成一个1~10的整数列表

代码语言:javascript
复制
list = [1,2,3,4,5,6,7,8,9,10]

或者,

代码语言:javascript
复制
list = range(1,11)

例子二:生成一个1~10的每个整数的平方数的列表

代码语言:javascript
复制
list = []
for num in range(1, 11):
    list.append(num*num)

虽然确实是实现了预期的需求,但是需要通过多行代码才能实现,过程非常繁琐,一点都不pythonic。

为了实现类似需求,python提供了一些高级特性来简化,就是列表推导式。

列表推导式

列表推导式(List Comprehensions)是python内置的非常简单且强大的可以用来轻松创建列表(List)的方法。

例子三:用列表推导式创建1~10的所有整数的平方数的列表

代码语言:javascript
复制
>>> list = [num*num for num in range(1,11)]
>>> list
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

可见,列表推导式的书写规则是,生成的元素放在语句前面,紧跟着的是for循环。

而且,在列表推导式的循环后面加上条件判断 。

列子四:创建1~10的所有偶数平方数的列表

代码语言:javascript
复制
>>> list = [num * num for num in range(1,11) if num%2 == 0]
>>> list
[4, 16, 36, 64, 100]

例子五:使用两个for循环将两个列表中的元素进行全排列,继而生成新的列表

代码语言:javascript
复制
>>> list = [char+num for char in ['a', 'b', 'c'] for num in ['1','2', '3']]
>>> list
['a1', 'a2', 'a3', 'b1', 'b2', 'b3', 'c1', 'c2', 'c3']

生成器表达式

基于列表继续扩展,如果列表元素的个数持续扩大,达到10万个,如此大的列表将占据巨大的内存。假设程序实际上只需要访问列表中其中的几个元素,那么列表占用的绝大多数内存空间都是多余的,纯属浪费。Python为了解决这个问题,引入生成器(generator)。

可以通过生成器表达式将列表改为一个生成器。列表一旦被创建,其包含的元素就实实在在地存在内存中,占据着内存空间,列表存放的是元素本身,而生成器存放的是算法,通过next()调用算法实时生成元素,因此生成器占用的内存空间很小。

将列表推导式的方括号[]改为小括号()即可创建一个生成器。

例子六:

代码语言:javascript
复制
>>> g = (num * num for num in range(1,6))
>>> g
<generator object <genexpr> at 0x0000018E0754F228>
>>> next(g)
1
>>> next(g)
4
>>> next(g)
9
>>> next(g)
16
>>> next(g)
25
>>> next(g)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

说明:可以看到,列表list一旦被创建,内存中就存放所有元素,而生成器g的元素内容将随着next()函数的调用实时生成,直到最后没有元素可生成时,抛出StopIteration错误。

生成函数器

除了表达式可以变为生成器之外,函数同样可以变为生成器。

例子七:编写一个函数,通过该函数可以计算出任意自然数的平方数。

代码语言:javascript
复制
#!usr/bin/env python
def square(input):
    list = []
    for num in range(input):
        list.append(num * num)
        print(list)
    return list

for num in square(5):
    print(num)

结果:

代码语言:javascript
复制
[0]
[0, 1]
[0, 1, 4]
[0, 1, 4, 9]
[0, 1, 4, 9, 16]
0
1
4
9
16

说明:可以看到square()函数在运行过程中会创建一个列表,假设想要计算的自然数变大,那么列表也会变大,此程序便会占据大量的内存,当自然数无限大时,程序将因无法分配到足够的内存而崩溃。

例子八:借助生成器,将square()函数改为生成器函数。

代码语言:javascript
复制
#!usr/bin/env python
def square(input):
    for num in range(input):
        print('before yield')
        yield num * num
        print('after yield')

for num in square(5):
    print(num)

结果:

代码语言:javascript
复制
before yield
0
after yield
before yield
1
after yield
before yield
4
after yield
before yield
9
after yield
before yield
16
after yield

说明:

  • 可以看到,使用生成器函数同样实现了与普通函数同样的功能。
  • 它们有如下区别:生成器代码更简洁。对比两者的代码,除了用于打印提示信息的代码之外,生成器的代码量更少,结构更为简洁。生成器内存占用极少。生成器并没有创建列表,更不会因为自然数的变大而消耗大量的内存;普通函数则面临严重的内存问题。运行方式不同。普通函数是顺序执行的,直到执行完最后一行语句或者遇到return语句就返回;而生成器函数则是遇到yield语句返回,再次执行时,从上次离开的地方继续执行。
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-05-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 一番码客 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 列表推导式
  • 生成器表达式
  • 生成函数器
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档