您好, 欢迎来到 !    登录 | 注册 | | 设为首页 | 收藏本站

Python for循环和迭代器行为

Python for循环和迭代器行为

您的怀疑是正确的:迭代器已被消耗。

实际上,您的迭代器是一个generator,这是一个对象,它 只能 被迭代 一次。

type((i for i in range(5))) # says it's type generator

def another_generator():
    yield 1 # the yield expression makes it a generator, not a function

type(another_generator()) # also a generator

它们高效的原因与“参考”告诉您下一步是什么无关。它们之所以有效,是因为它们仅根据请求生成一个项目。所有项目都不是一次生成的。实际上,您可以拥有一个无限生成器:

def my_gen():
    while True:
        yield 1 # again: yield means it is a generator, not a function

for _ in my_gen(): print(_) # hit ctl+c to stop this infinite loop!

其他一些更正可以帮助您增进理解:

您可以通过for这种方式“手动”在python中实现循环(可能并不完美,但足够接近):

try:
    temp = iterable.__iter__()
except AttributeError():
    raise TypeError("'{}' object is not iterable".format(type(iterable).__name__))
else:
    while True:
        try:
            _ = temp.__next__()
        except StopIteration:
            break
        except AttributeError:
            raise TypeError("iter() returned non-iterator of type '{}'".format(type(temp).__name__))
        # this is the "body" of the for loop
        continue

上面的代码与您的示例代码几乎没有区别。

实际上,for循环中最有趣的部分不是for,而是in。单独使用in会产生与产生不同的效果forin,但是,了解in使用其参数的作用非常有用,因为它for in实现了非常相似的行为。

单独使用时,in关键字首先调用对象的__contains__method,这是另一个“魔术方法”(请注意,使用时将跳过此步骤for in)。使用in一个容器本身,你可以做这样的事情:

1 in [1, 2, 3] # True

‘He’ in ‘Hello’ # True 3 in range(10) # True ‘eH’ in ‘Hello’[::-1] # True

如果可迭代对象不是容器(即它没有__contains__方法),则in下一步尝试调用该对象的__iter__方法。如前所述:该__iter__方法返回Python中称为iterator的值。基本上,迭代器是一个对象,您可以next()在1上使用内置的泛型函数生成器只是迭代器的一种类型。

如果__iter__成功调用,则in关键字将函数next()一次又一次地应用于可迭代对象。(请记住:可迭代对象可以是生成器,也可以是容器对象的迭代器,或任何其他可迭代对象。)实际上,更确切地说,它调用迭代器对象的__next__方法

如果您希望创建自己的对象类型以进行迭代(即,您可以使用,也可以forinin在其上使用),那么了解生成器中yield使用的关键字(如上所述)很有用。

class MyIterable():
    def __iter__(self):
        yield 1

m = MyIterable()
for _ in m: print(_) # 1
1 in m # True

yield函数方法变成生成器而不是常规函数/方法的存在。__next__如果使用生成器(它会__next__自动提供),则不需要该方法

如果您希望创建自己的容器对象类型(即可以单独使用in它,但不能使用for in),则只需要该__contains__方法即可。

class MyUselessContainer():
    def __contains__(self, obj):
        return True

m = MyUselessContainer()
1 in m # True
'Foo' in m # True
TypeError in m # True
None in m # True

1请注意,要成为迭代器,对象必须实现迭代器协议。这仅意味着__next____iter__方法都必须 正确 实现(生成器带有“免费”此功能,因此您在使用它们时无需担心)。还要注意,该___next__方法实际上next在Python 2中(没有下划线)

2请参 见此答案以了解创建可迭代类的不同方法

python 2022/1/1 18:41:35 有259人围观

撰写回答


你尚未登录,登录后可以

和开发者交流问题的细节

关注并接收问题和回答的更新提醒

参与内容的编辑和改进,让解决方法与时俱进

请先登录

推荐问题


联系我
置顶