python迭代器,生成器,列表生成式

列表生成式

列表生成式即List Comprehensions,是Python内置的非常简单却强大的可以用来创建list的生成式。

例如:

>>> [x * x for x in range(1, 11)]
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

生成器

1.定义

一个函数调用时返回一个迭代器,那这个函数就叫做生成器(generator),如果函数中包含yield语法,那这个函数就会变成生成器

2.作用

这个yield的主要效果呢,就是可以使函数中断,并保存中断状态,中断后,代码可以继续往下执行,过一段时间还可以再重新调用这个函数,从上次yield的下一句开始执行。

另外,还可通过yield实现在单线程的情况下实现并发运算的效果

例如1 :保存中断状态

def cash_out(amount):
    while amount > 0:
        amount -= 1
        yield 1
    return "done"


ATM = cash_out(5)
try:
    print("取到钱 %s 万" % ATM.__next__())
    print("花掉花掉!")	
    print("取到钱 %s 万" % ATM.__next__())
    print("取到钱 %s 万" % ATM.__next__())
    print("花掉花掉!")
    print("取到钱 %s 万" % ATM.__next__())
    print("取到钱 %s 万" % ATM.__next__())
    print("取到钱 %s 万" % ATM.__next__())  # 到这时钱就取没了,再取就报错了
    print("取到钱 %s 万" % ATM.__next__())
except StopIteration as e:
    print("%s" %e.value)
#输出结果
取到钱 1 万
花掉花掉!
取到钱 1 万
取到钱 1 万
花掉花掉!
取到钱 1 万
取到钱 1 万
done

例如2:单线程进行并发运算

import time


def consumer(name):
    print("%s 准备吃包子啦!" % name)
    while True:
        baozi = yield

        print("包子[%s]来了,被[%s]吃了!" % (baozi, name))
        
def producer(name):
    c = consumer('A')
    c2 = consumer('B')
    c.__next__()
    c2.__next__()
    print("老子开始准备做包子啦!")
    for i in range(10):
        time.sleep(1)
        print("做了2个包子!")
        c.send(i)
        c2.send(i)
        
producer("alex")

3.返回值

yield是生成器返回值

return返回值是StopIterator错误抛出的值

迭代器

1.特点

  1. 访问者不需要关心迭代器内部的结构,仅需通过next()方法不断去取下一个内容
  2. 不能随机访问集合中的某个值 ,只能从头到尾依次访问
  3. 访问到一半时不能往回退
  4. 便于循环比较大的数据集合,节省内存
>>> a = iter([1,2,3,4,5])
>>> a
<list_iterator object at 0x101402630>
>>> a.__next__()
1
>>> a.__next__()
2
>>> a.__next__()
3
>>> a.__next__()
4
>>> a.__next__()
5
>>> a.__next__()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

2.常见的迭代器

py3

#range使用了迭代器,每次需要获取才调用函数
>>> range(10)
range(0, 10)
#文件读取的时候,read()和readlines()将所有内容都读取到列表,会占用大量内存
#使用迭代器,一行行的读和操作,性能更优
f = open("1.txt")
for i in f:
      print(i)

py2

>>> range(10)
[0,1,2,3,4,5,6,7,8,9]

>>> xrange(10)
range(0, 10)

3.可迭代对象

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

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

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

>>> from collections import Iterable
>>> isinstance([], Iterable)
True
>>> isinstance({}, Iterable)
True
>>> isinstance('abc', Iterable)
True
>>> isinstance((x for x in range(10)), Iterable)
True
>>> isinstance(100, Iterable)
False

为什么listdictstr等数据类型不是Iterator

这是因为Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。

Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。

listdictstrIterable变成Iterator可以使用iter()函数:

#list dict string不是迭代器
>>> from collections import Iterator
>>> isinstance((x for x in range(10)), Iterator)
True
>>> isinstance([], Iterator)
False
>>> isinstance({}, Iterator)
False
>>> isinstance('abc', Iterator)
False

#list dict string可以转换为迭代器
>>> isinstance(iter([]), Iterator)
True
>>> isinstance(iter('abc'), Iterator)
True
原文地址:https://www.cnblogs.com/akiz/p/11144306.html