初学Python——列表生成式、生成器和迭代器

一、列表生成式

假如现在有这样一个需求:快速生成一个列表[1,2,3,4,5,6,7,8,9,10],该如何实现?

在不知道列表生成式的情况下,可能会这样写:

a=[1,2,3,4,5,6,7,8,9,10]

如果要每个值+1呢?可能会这样:

for index,i in enumerate(a):
    a[index] +=1
print(a)

不够方便,这里讲一个快速生成列表的方法:列表生成式。意思就是立即生成列表。

生成一个1到10的列表:

a = [i+1 for i in range(10)]
print( a)
# output:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

生成一个2~20的偶数列表:

a=[ i*2 for i in rang(1,11)]
print(a)
# output:
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]

它相当于:

a=[]
for i in range(1,11): #列表生成式
    a.append(i*2)
print(a)

生成的列表已经存在在内存中。

二、生成器

通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。

所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的列表,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。

要创建一个生成器,只需要把列表生成式中的 [ ] 改成 ( ) 即可。

b=[i*2 for i in rang(10)] # 列表生成式
print(b)

c=( i*2 for i in range(10) ) #生成器
print(c)

# output:
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
<generator object <genexpr> at 0x000001D0089B45C8>

输出c,得到的是数据类型说明和它的内存地址。

生成器只是名义上生成一个列表,但实际上却没有占用那么大内存,生成器只有调用的时候才会生成相应的数据。

如果要打印生成器的数据,则需要.__next__()方法

print(c.__next__()) # 输出第一个数
0
print(c.__next__()) # 输出第二个数
1
print(c.__next__()) # 输出第三个数
2
print(c.__next__()) # 输出第四个数
3
print(c.__next__()) # 输出第五个数
4

如果我只需要当中的最后一个数据呢?能不能直接输出?

抱歉,不能。而且,生成器的数据只能从前往后去访问,不能从后往前去访问,在内存中只保留一个值,也就是说,访问过的数据已经无法再次访问。

如果生成器有很多的数据,要全部输出,有没有简便的写法?

抱歉,没有,您只能一个一个地输出。

当然,像上面那样不断调用.__next__()还是太坑爹了,可以用for去迭代它(生成器也是可迭代对象):

 g = (x * x for x in range(10))
for n in g:
    print(n)

那,,我还要生成器有卵用??

还是有点卵用的,生成器一般依托于函数实现,比如,我先定义一个函数fib(),函数内定义了数列的推算规则

def fib(max):
    n, a, b = 0, 0, 1
    while n < max:
        print(b)
        a, b = b, a + b
        n = n + 1
    return ‘done‘

# 注释:
a, b = b, a + b  相当于:
t = (b, a + b) # t是一个tuple
a = t[0]
b = t[1]
它不必写出显式变量 t

如果给fib()传参10,它将输出一连串的数字,可以组成一个数列:

1,1,2,3,5,8,13,21,34,55

此时的fib函数,已经非常接近生成器了,只需要一个yield即可,

def fib(max):  #当函数中有yield出现时,不能将其简单视为函数,是一个生成器。
    "生成器"
    n,a,b=0,0,1
    while n<max:
        yield b  #yield保存了函数当前的中断状态,返回当前b的值
        a,b=b,a+b
        n=n+1 #计数器
    return "done"

此时,fib(10)是一个生成器,

f = fib(6)
print(f)
<generator object fib at 0x104feaaa0>

这里最难理解的就是generator和函数的执行流程不一样。函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。

来一个一个地输出它的值:

f=fib(10)
print(f)
print(f.__next__())
print(f.__next__())
print(f.__next__())
print(f.__next__())

因为只能一个一个地输出,且不能得知长度,所以总会有越界的时候,会报一个异常StopIteration,导致程序停止

所以需要捕获异常:

while 1:
    try: #如果没有出现异常,执行下面语句
        x=next(g)
        print("g:",x)
    except StopIteration as e: #如果出现异常StopIteration,把它赋给e,执行下面的语句
        print(e.value)
        break

前面讲到,生成器只能一个一个地取出数据,在fib函数执行过程中会中断,为什么要这样呢?有什么用吗?

它厉害在:可以在单线程的情况下实现并发效果,举个例子:

import time

def custumer(name):
    print("{0}准备来吃包子了".format(name))
    while 1:
        baozi = yield    #每次运行到这一行时都会中断
        print("包子{0}来了,被{1}吃掉了".format(baozi,name))

def producer(name):
    c1=custumer("老大")
    c2=custumer("老二")
    c1.__next__()
    c2.__next__()    # next 只是在调用yield
    print("{0}开始做包子啦!".format(name))
    for i in range(1,15,2):
        time.sleep(1)
        print("做了两个包子")
        c1.send(i)     # send 调用yield的同时给它传值
        c2.send(i+1)

producer("alex")

如果在自己的解释器上执行,会发现一个程序有三个任务交错切换运行,看上去就像三个任务同时在进行。

三、迭代器

我们已经知道,可以直接作用于for循环的数据类型有以下几种:

一类是集合数据类型,如listtupledictsetstr等;

一类是generator,包括生成器和带yield的generator function。

这些可以直接作用于for循环的对象统称为可迭代对象:Iterable

可以使用isinstance()判断一个对象是否是Iterable对象。

for循环本质上时不断调用next()函数实现的:

a=[1,2,3,4,5]
for x in a:
    print(x)
#完全等价于
it=iter(a) # 将列表转化成迭代器对象
while 1:
    try:
        x=next(it)  #获得下一个值
        print(x)
    except StopIteration:
        break #遇到StopIteration异常就跳出循环

在文件操作时,

for line in f:
    print(line)

每次输出其实都是调用next()函数,在Python3中已经看不出是一个迭代器了。

原文地址:https://www.cnblogs.com/V587Chinese/p/9033201.html

时间: 2024-10-09 00:48:33

初学Python——列表生成式、生成器和迭代器的相关文章

python列表生成式&amp;生成器&amp;迭代器

一.列表生成式 什么是列表生成式? 列表生成式是快速生成列表的一种方式.(貌似有些废话) 更专业点的说法:列表生成式即List Comprehensions,是Python内置的非常简单却强大的可以用来创建list的生成式. 在python2.7里 举个例子,要生成list [1,2,3,4,5],可以用range(1,6) >>> range(1,6) [1, 2, 3, 4, 5] 但是如果要生成[1x1,2x2,3x3,4x4,5x5]怎么做呢? 普通青年做法: >>&

python列表生成式、生成器,迭代器与二分法

一.列表生成式 列表生成式是快速生成一个列表的一些公式 列表生成式的书写格式:[x*x for x in range(1 , 11)] 列表生成式语法是固定的,[]里面for 前面是对列表里面数据的运算操作,后面跟平常for循序一样遍历去读取.运行后会自动生成新的列表 一般列表生成式 list1 = list(range(1,10)) #不使用列表生成式生成列表 list2 = [x for x in range(1,10)] #使用列表生成式生成列表 print(list1) print(li

python高级特征:列表生成式;generator, 迭代器。

Python高级特性 列表生成式:不过一种语法糖 生成器:不过一个方法 迭代器: 列表生成式 Python内置的函数,来创建list. 简单的生成: >>> list(range(1,11)) [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 复杂的生成:增加一个for循环. >>> a = [x*x for x in range(1, 11)] >>> a [1, 4, 9, 16, 25, 36, 49, 64, 81, 100] 还

Python 列表生成式,函数,字符串,文件操作,生成器

知识点 1 ==与is区别:Python中对象包含的三个基本要素,分别是:id(身份标识).type(数据类型)和value(值). ==只比较值,而is比较身份标识也就是内存地址,而且在is比较中关于数据类型也就是只有数值型和字符串型的情况下,a is b才为True,当a和b是tuple,list,dict或set型时,a is b为False. 2 浅拷贝和深拷贝:需要使用copy模块 浅拷贝:copy()方法实现 1.对于不可变类型 Number String Tuple,浅复制仅仅是地

Python列表生成式和生成器

[1]列表生成器:列表生成式就是一个用来生成列表的特定语法形式的表达式. 1.基础语句结构:[exp for iter_var in iterable例如:a=[f(x) for x in range(10)] 2.工作过程: 迭代iterable中的每个元素:每次迭代都先把结果赋值给iter_var,然后通过exp得到一个新的计算值:最后把所有通过exp得到的计算值以一个新列表的形式返回. 相当于这样的过程:L = [] for iter_var in iterable: L.append(e

s14 第4天 关于python3.0编码 函数式编程 装饰器 列表生成式 生成器 内置方法

python3 编码默认为unicode,unicode和utf-8都是默认支持中文的. 如果要python3的编码改为utf-8,则或者在一开始就声明全局使用utf-8 #_*_coding:utf-8_*_ 或者将字符串单独声明: a = "中文".encode("utf-8") 函数式编程 函数式编程中的函数指代的是数学中的函数. 函数式编程输入如果确定,则输出一定是确定的.函数中并没有很多逻辑运算 python是一个面向对象的语言,只是一部分支持函数式编程.

Python基础06 - 生成器、迭代器

@@@文章内容参照老男孩教育 Alex金角大王,武Sir银角大王@@@ 一.生成器 列表生成式 1 a = [i * 2 for i in range(10)] 2 print(a) 3 # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18] 生成器 通过列表生成式,我们可以直接创建一个列表.但是,受到内存限制,列表容量肯定是有限的,而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大数元素占用的空间都是浪费的. 所以,

python 列表生成式

列表特性:列表是一次性生成的 a = [1,2,3,4,5,6,7,8,9] 或 [ i*2 for i in range(10)]  ###--->列表生成式 ===[2,4,6,8,10,12,14,16,18,20]=== 两个列表的区别: 1列表是写死的,2列表可以里面做一些操作把相应的东西输出出来 列表生成式目的是为了使代码更简洁,且可以实现更复杂的功能,如将i的值传至函数中 [fun(i)  for i in range(10)] 生成式:通过生成式可以直接创建一个列表,但受内存大小

python\列表和生成器表达式

一.协程函数的应用 写一个装饰器用于让协程函数不需要输入再执行一次next()函数 分析: 在装饰器中生成该协程函数的生成器, 并且执行一次next()函数 def firstNext(func): def wrapper(*args, **kwargs): g = func(*args, **kwargs) next(g) return g return wrapper @firstNext def eater(name): print("{} start to eat".forma