简体   繁体   English

对python中的“迭代器”感到困惑

[英]Confused about “iterators” in python

I am studying python with the book Beginning Python: From Novice to Professional , and I get confused about the section discussing iterators . 我正在使用Beginning Python:从新手到专业的书学习python,我对讨论iterators的部分感到困惑。 There is an example in this section: 本节有一个例子:

>>> Class Fibs:
...    def __init__(self):
...        self.a = 0
...        self.b = 1
...    def __next__(self):
...        self.a, self.b = self.b, self.a + self.b
...        return self.a
...    def __iter__(self):
...        return self
...
>>> fibs = Fibs()
>>> for f in fibs:
...     if f > 1000:
...         print(f)
...         break
...
1597

To be honest, I only know that fibs is an object with methods __next__ and __iter__ , but have no idea about what happens in each step of the loop. 说实话,我只知道fibs是一个方法__next____iter__的对象,但不知道循环的每一步发生了什么。 And I made a test: 我做了一个测试:

>>> isinstance(f, Fibs)
False
>>> f is fibs
False
>>> isinstance(f, int)
True
>>> fibs.a
1597

This makes me much more confused! 这让我更加困惑! Why the boolean value of f is fibs is False ? 为什么f is fibs的布尔值f is fibsFalse And why fibs.a become 1597 after the execution of the loop?(Is the method __next__ automatically called in the loop?) Thanks in advance. 为什么在执行循环后fibs.a变为1597?(方法__next__是否在循环中自动调用?)提前感谢。

 1  fibs = Fibs()
 2  for f in fibs:
 3      if f > 1000:
 4          print(f)
 5          break

Line 1 creates a Fibs() object, calling __init__() . 第1行创建一个Fibs()对象,调用__init__() Line 2 calls __iter__() , which returns an iterator object (in this case, just fibs itself). 第2行调用__iter__() ,它返回一个迭代器对象(在本例中,只是fibs本身)。 The interpreter will then begin calling the __next__() method repeatedly; 然后解释器将重复调用__next__()方法; it returns self.a , a plain number, which is assigned to the loop variable f (so of course it's not a Fibs() object and certainly not the one named fibs). 它返回一个普通数字self.a ,它被分配给循环变量f (当然它不是Fibs()对象,当然也不是名为fibs的那个)。 When that value reaches 1000, the if clause will fire, print the result, and break out of the loop. 当该值达到1000时,将触发if子句,打印结果并跳出循环。

And why fibs.a become 1597 after the execution of the loop? 为什么在执行循环后fibs.a变为1597?

Well this is because it is going through the Fibonacci sequence and this is the first number over 1000 in the sequence. 那么这是因为它正在经历Fibonacci序列 ,这是序列中第一个超过1000的数字。

0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597 , 2584 ... 0,1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584 ...

On enter to the loop interpreter calls __iter__ method. 在输入循环解释器时调用__iter__方法。 On every loop step interpreter calls __next__ method of Fibs . 在每个循环步骤中,解释器调用Fibs __next__方法。

Yes, the loop automatically calls __next__ . 是的,循环自动调用__next__

The for loop does this to the given object: for循环对给定对象执行此操作:

# turn the object into an iterator
iterator = iter(given_object)
while True:
    try:
        # try to get the next value
        next_value = next(iterator)
    except StopIteration
        # for loop is done, run the `else:` block if there is any
        run_for_else_suite()
        break
    else:
        # set the loop target to `next_value`
        assign_next_value(next_value)
        continue = run_loop_body()
        if not continue:
            break

The iter() function calls given_object.__iter__() , and the next() function calls given_object.__next__() ; iter()函数调用given_object.__iter__() ,而next()函数调用given_object.__next__() ; these functions offer some extra functionality and are the proper way of calling into the iterator API. 这些函数提供了一些额外的功能,是调用迭代器API的正确方法。

So, in each loop iteration, f is assigned the value that the Fib.__next__ method returned. 因此,在每次循环迭代中, f被赋予Fib.__next__方法返回的值。

You can also see that Fib is its own iterator; 你还可以看到Fib是它自己的迭代器; __iter__ returns self . __iter__返回self Other types can return a dedicated iterator object; 其他类型可以返回专用的迭代器对象; lists do, for example: 列表做,例如:

>>> iter([])
<listiterator object at 0x129516610>

Returning dedicated iterators lets you create multiple 'views' on an object where each iterator maintains its own position, like nested loops: 返回专用迭代器允许您在对象上创建多个“视图”,其中每个迭代器都保持自己的位置,如嵌套循环:

lst = [1, 2, 3]
for i in lst:
    for j in lst;
        print (i, j)  # prints (0, 0), (0, 1), (0, 2), (0, 3), (1, 0), etc.

or you can explicitly reuse the iterator: 或者您可以显式重用迭代器:

lst = [1, 2, 3]
lst_iter = iter(lst)
for i in lst_iter:
    for j in lst_iter:
        print (i, j)  # prints (0, 1), (0, 2)
for f in fibs

implicitly calls fibs.__iter__ and binds f to all the objects that it yields, in turn. 隐式调用fibs.__iter__fibs.__iter__f绑定到它产生的所有对象。 None of these objects are instances of Fibs , let alone equal to fibs . 这些对象都不是Fibs实例,更不用说等于fibs The whole is (roughly) equivalent to 整体(大致)相当于

# boilerplate, implicit in the "for" notation
__iterator = iter(fibs)
while True:
    try:
        f = next(__iterator)
    except StopIteration:
        break

    # your code, with f now bound to what the iterator yielded
    if f > 1000:
        print(f)
        break

( iter and next are the clean ways to call __iter__ and __next__ , respectively.) iternext分别是调用__iter____next__的简洁方法。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM