for循环如何评估其参数

时间:2016-02-16 17:47:16

标签: python python-2.7 python-3.x for-loop

我的问题非常简单。

for循环是否每次都会计算它使用的参数?

如:

for i in range(300):

python是否为此循环的每次迭代创建了300个项目的列表?

如果是,这是一种避免它的方法吗?

lst = range(300)
for i in lst:
    #loop body

对于像这样的代码示例也一样。

for i in reversed(lst):

for k in range(len(lst)):

每次都应用反向过程,还是每次迭代计算的长度? (我问这个python2和python3)

如果没有,Python如何在迭代迭代时评估迭代的变化?

3 个答案:

答案 0 :(得分:7)

不用担心,迭代器只会被评估一次。它最终大致相当于这样的代码:

it = iter(range(300))
while True:
    try:
        i = next(it)
    except StopIteration:
        break
    ... body of loop ...

请注意,它不是相当等效,因为break的工作方式不同。请注意,您可以将else添加到for循环,但这不适用于上述代码。

答案 1 :(得分:4)

创建的对象取决于循环返回的Iterable的__iter__方法。

通常Python在迭代Iterable时创建一个Iterator,Iterable本身不是Iterator。在Python2中,range返回一个列表,该列表是一个Iterable,并且有一个__iter__方法,它返回一个Iterator。

>>> from collections import Iterable, Iterator
>>> isinstance(range(300), Iterable)
True
>>> isinstance(range(300), Iterator)
False
>>> isinstance(iter(range(300)), Iterator)
True

for in sequence: do something语法基本上是执行此操作的简写:

it = iter(some_iterable) # get Iterator from Iterable, if some_iterable is already an Iterator, __iter__ returns self by convention
while True:
    try:
        next_item = next(it)
        # do something with the item
    except StopIteration:
        break

这是一个包含一些打印语句的演示,用于阐明使用for循环时发生的情况:

class CapitalIterable(object):
    'when iterated over, yields capitalized words of string initialized with'
    def __init__(self, stri):
        self.stri = stri

    def __iter__(self):
        print('__iter__ has been called')
        return CapitalIterator(self.stri)

        # instead of returning a custom CapitalIterator, we could also
        # return iter(self.stri.title().split())
        # because the built in list has an __iter__ method

class CapitalIterator(object):
    def __init__(self, stri):
        self.items = stri.title().split()
        self.index = 0

    def next(self): # python3: __next__
        print('__next__ has been called')
        try:
            item = self.items[self.index]
            self.index += 1
            return item
        except IndexError:
            raise StopIteration

    def __iter__(self):
        return self

c = CapitalIterable('The quick brown fox jumps over the lazy dog.')
for x in c:
    print(x)

输出:

__iter__ has been called
__next__ has been called
The
__next__ has been called
Quick
__next__ has been called
Brown
__next__ has been called
Fox
__next__ has been called
Jumps
__next__ has been called
Over
__next__ has been called
The
__next__ has been called
Lazy
__next__ has been called
Dog.
__next__ has been called

如您所见,__iter__仅被称为一次,因此只创建了一个Iterator对象。

答案 2 :(得分:0)

在这种情况下,Range会创建一个包含300个整数的数组。它不会创建300次300次的数组。并不是每一项都有效。如果你使用xrange,它将创建一个可迭代的对象,它不会占用几乎同样多的内存。 https://docs.python.org/2/library/functions.html#xrange

example.py

for i in xrange(300): #low memory foot print, similar to a normal loop
    print(i)