繁体   English   中英

根据 class 理解 __iter__() 方法

[英]Understanding the __iter__() method in terms of a class

我目前正在尝试了解有关 for 循环和生成器的更多信息,并且遇到了这段代码:

class OdeStore:
    def __init__(self,data):
        self.data=data #list of form [[t0,u0],[t1,u1]...]
    def __iter__(self):
        for t,u in self.data: #specify the data iterated over
            yield u #how it is yielded
        
store=OdeStore([[0,1],[0.1,1.1],[0.2,1.3]])
for u in store:
   print(u)

如果我的理解是正确的,我们可以在__iter__()来定义当涉及 class 的实例时 for 循环将如何作用。 在这种情况下,我们 state ,一旦我们遍历 OdeStore class 的实例,将产生嵌套列表的第二个条目。 我对代码的解释是否正确? 我的困惑主要来自于在__iter__的定义中包含一个 for 循环。

例如,如果我们现在应用 list() function,我们得到:

list(store) # returns [1, 1.1, 1.3]

我试图找出 list() function 是如何运作的,但我想它将 object 的条目附加到一个空列表(或其中的一些)。

也许插入一些打印语句将提供更多信息:

class OdeStore:
    def __init__(self,data):
        self.data=data #list of form [[t0,u0],[t1,u1]...]
    def __iter__(self):
        print("  starting __iter__")
        for t,u in self.data: #specify the data iterated over
            print(f"  iter at {t},{u}, returning {u}")
            yield u #how it is yielded
        
print("iterating over OdeStore")
store=OdeStore([[0,1],[0.1,1.1],[0.2,1.3]])
for u in store:
   print(u)

print("starting list")
l = list(store)
print(f"list: {l}")

Output:

iterating over OdeStore
  starting __iter__
  iter at 0,1, returning 1
1
  iter at 0.1,1.1, returning 1.1
1.1
  iter at 0.2,1.3, returning 1.3
1.3
starting list
  starting __iter__
  iter at 0,1, returning 1
  iter at 0.1,1.1, returning 1.1
  iter at 0.2,1.3, returning 1.3
list: [1, 1.1, 1.3]

您可以看到对__iter__的初始调用(在 for 循环开始时进行)并且__iter__内的 for 循环被 yield 调用“暂停”。 从概念上讲,执行的 state 由 yield 调用保存,将一个值返回给 for 循环,并在下一次 for 循环调用迭代器时使用保存的上下文继续执行。

我试图找出 list() function 是如何运作的,但我想它将 object 的条目附加到一个空列表(或其中的一些)。

我相信这在概念层面上是正确的。 从 output 可以看出,在列表构建期间,会创建一个迭代器并遍历 OdeStore。

也许以这种方式分解它会使它更加具体。 让我们把我们的脚本改成这样:

class OdeStore:
    def __init__(self,data):
        self.data=data #list of form [[t0,u0],[t1,u1]...]
    def __iter__(self):
        print("  starting __iter__")
        for index in range(0, len(self.data)):
            print(f"  iter at index {index}, returning {self.data[index][1]}")
            yield self.data[index][1]
        #for t,u in self.data: #specify the data iterated over
        #    print(f"  iter at {t},{u}, returning {u}")
        #    yield u #how it is yielded
        
store=OdeStore([[0,1],[0.1,1.1],[0.2,1.3]])
print("Creating iterator")
iter = iter(store)
print("calling next 1st time")
print(next(iter))
print("calling next 2nd time")
print(next(iter))
print("calling next 3rd time")
print(next(iter))
print("calling next 4th time")
print(next(iter))

Output:

Creating iterator
calling next 1st time
  starting __iter__
  iter at index 0, returning 1
1
calling next 2nd time
  iter at index 1, returning 1.1
1.1
calling next 3rd time
  iter at index 2, returning 1.3
1.3
calling next 4th time
Traceback (most recent call last):
  File "./odestore.py", line 25, in <module>
    print(next(iter))
StopIteration

从概念上讲,每个yield都在节省指数并返回计算值。 当再次调用迭代器时,这个存储的索引会增加(因为__iter__中的for循环)。 调用 yield 保存index的新值并返回计算值。 当我们用完值时, __iter__返回而不是产生,并且迭代器实现 class (称为generator )引发StopIteration异常。

暂无
暂无

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

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