Python迭代器和生成器

迭代器(iterator)

在Python中,迭代(iteration)的概念是建立在容器的基础上的,所有的容器都是可迭代的(iterable)。容器是对象的集合,列表、元组、字典、集合等都是容器。不同容器之间的区别在于内部数据结构的实现方式不同。可迭代对象(列表、元组、字典、集合等)通过iter(iterable)函数返回一个迭代器,next(iterator)函数可实现在迭代器中遍历。next(iterator)函数要么返回当前对象的下一个对象,要么抛出StopIteration的错误。

container = [[1, 2, 3, 4], (1, 2, 3, 4), set([1, 2, 3, 4]), {1 : 'a', 2 : 'b'}, 'abcd']

for it in container:
    it = iter(it)
    print(it)
    while True:
        try:
            print(next(it))
        except StopIteration:
            break
        
# 输出
# <list_iterator object at 0x7f5d5547a6d8>
# 1 2 3 4
# <tuple_iterator object at 0x7f5d5547a6d8>
# 1 2 3 4
# <set_iterator object at 0x7f5d553df8b8>
# 1 2 3 4
# <dict_keyiterator object at 0x7f5d55c62d18>
# 1 2
# <str_iterator object at 0x7f5d5530f278>
# a b c d

生成器(generator)

生成器实质上也是一个迭代器,只不过在迭代器中的数据都是已经存在的,而生成器是在需要数据时才临时生成数据。相比于迭代器,这样的特性有利于节省内存空间。
例如,[i for i in range(1000000)]生成一个包含一百万元素的列表,每个元素都存在于内存中,占据了大量的空间。但是我们有时候并不需要在内存同时保存这些元素,例如对列表中的所有元素求和,我们每次只需要知道下一个元素的值并对其进行累加,累加完后即可丢弃,然后依次迭代下去,就可以求出所有元素的和。 生成器的写法如下,和迭代器相比,只不过把中括号换成了小括号。

iterator = [i for i in range(1000000)] # 迭代器
generator = (i for i in range(1000000)) # 生成器

下面是两个生成器的例子,在Python中,带有yield关键字的函数称为生成器。当调用生成器时,每次遇到yield时函数会暂停并保存当前位置的信息,然后返回yield当前值。在下次执行next()时从之前保存的位置继续执行。

def generator(n):
    i = 1
    while i < n:
        yield i
        i += 1

g = generator(10)
print(g)

while True:
    try:
        print(next(g))
    except StopIteration:
        break

# 输出
# <generator object generator at 0x7ff57086b9e8>
# 1 2 3 4 5 6 7 8 9 10
def generator(s, l):
    for i, v in enumerate(s):
        if v == l:
            yield i

g = generator('OrangeApple', 'e')

while True:
    try:
        print(next(g))
    except StopIteration:
        break

# 输出
# 5 10

现在有一个判断子序列的问题。如果第一个列表中的元素在第二个列表中依次出现,则第一个列表就是第二个列表的子序列。例如[1, 3, 5]是[1, 2, 3, 4, 5]的子序列,[1, 5, 3]不是[1, 2, 3, 4, 5]的子序列。
常规的解法是通过两个指针分别指向两个列表的开端,然后遍历第二个列表。当两个指针指向的元素相同时,就把第一个指针向后移动一位,直到指针指向最后一个元素的下一位时,返回True,否则返回False。

def isSubsequence(s, t):
    p = 0
    for i in range(len(t)):
        if t[i] == s[p]:
            p += 1
            if p == len(s):
                return True
    return False

如果利用生成器来解,则只需要两行。

def is_subsequence(s, t):
    t = iter(t)
    return all(i in t for i in s)

首先通过t = iter(t)将t转化为一个迭代器,然后对s中的每个元素,依次判断该元素是否在t中。all()表示括号中的所有元素为True时才返回True。
这里i in t是代码的关键。表示依次遍历t中的元素,如果某个元素等于i,则返回True,否则遍历结束后返回False。如果遍历结束前某个元素等于i,则中断遍历,返回True。当第二次执行这条语句时(即判断下个元素是否在t中),将直接从上次遍历中断的位置继续执行。 也就是说生成器只能遍历一次,且不可逆。当遍历中断时,下次继续遍历只会从上次中断的位置开始,而不会从头开始。可以验证一下:

t = [1, 2, 3, 4, 5]
t = iter(t)
print(2 in t)
print(4 in t)
print(3 in t)

# 输出
# True
# True
# False
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值