2016-11-05 47 views
2

为什么一个课程需要定义__iter__()返回自我,以获得该类的迭代器?为什么一个类需要__iter __()来返回一个迭代器?

class MyClass: 
    def __init__(self): 
     self.state = 0 

    def __next__(self): 
     self.state += 1 
     if self.state > 4: 
      raise StopIteration 
     return self.state 

myObj = MyClass() 
for i in myObj: 
    print(i) 

控制台日志:

Traceback (most recent call last): 
    for i in myObj: 
TypeError: 'MyClass' object is not iterable 

答案https://stackoverflow.com/a/9884259/4515198

迭代器是与下一个(Python的2)或__next__(Python 3中)的方法的对象。

加入以下的任务:

def __iter__(self): 
    return self 

是返回一个迭代,或者类,它定义了__next__()方法的对象。

但是,当MyClass在myObj = MyClass()行中实例化时,不是返回已由__new__()方法完成的MyClass对象的任务(它定义了__next__()方法)?

不会定义__next__()方法的类的对象是自己的迭代器吗?

我已经研究了问题What is the use of returning self in the __iter__ method?Build a Basic Python Iterator,但我仍然无法理解让方法返回自我的原因。

回答

2

不说,已经由__new__()方法

都能跟得上完成,__new__仅仅是另一种方法,它不会自动为对象创建__iter__

不会定义__next__()方法的类的对象是自己的迭代器吗?

不一定,因为您的第一堂课定义为__next__但不是__iter__显示。 __next__需要如果您需要支持迭代,因为它会生成值。 __iter__是需要的,因为这就是for语句中的一个对象所要求的,以便它获得一个迭代器。

你可以有一个类,只定义__next__和有些作品(它是有限的),但它需要从某人__iter__返回。例如,类MyClass返回类CustomIter只定义__next__

class MyClass: 
    def __iter__(self): 
     return CustomIter() 

class CustomIter(object): 

    def __init__(self): 
     self.state = 0 

    def __next__(self): 
     self.state += 1 
     if self.state > 4: 
      raise StopIteration 
     return self.state 

你需要一个对象,将返回另一个对象上定义一个__iter__(可能是本身)上__next__定义。


如果你的类定义__iter__为:

def __iter__(self): return self 

,那么你需要在type(self)(类)定义__next__因为你返回的实例本身。 __next__将会在self上被调用,直到不能产生更多的值。

另一种情况是当__iter__只是返回另一个定义为__next__的对象(按照我的第一个示例)。您也可以通过制作__iter__生成器来做到这一点。

例如:

class MyClass: 
    def __init__(self): 
     self.state = 0 

    def __iter__(self): 
     for i in range(10): yield i 

没有定义__next__。当iter被调用它,但:

g = iter(MyClass()) 

它返回一个发电机g定义__next__

g = iter(MyClass()) 

g.__next__() # 0 
g.__next__() # 1 
+0

我的意思是在“__new __()'方法中已经做过的事情”是,当已经创建了__new __() MyClass的一个对象,为什么我们需要通过'__iter __()'来再次返回MyClass对象? –

+0

当我得到它时,像'for' ** _必须_ **这样的循环调用'__iter __()'方法来获取MyClass的实例或任何类的实例。这是它在python中的工作方式吗? –

+0

如果存在,@ thebeliever3。您在问题主体中的链接中提供了回退选项(例如,如果没有找到__iter__,则尝试'__getitem__'。) –

6

答案的问题为什么__iter __()方法是必要的是对于for-loops总是通过调用iter()对象得到一个迭代器。这就是为什么即使是迭代器也需要使用for循环来处理迭代器。在调用iter(),然后在结果迭代器上调用__next __()来获得一个值。

用于创建iterables和迭代器的规则是:

1)Iterables具有__iter __()方法,该方法返回迭代器。

2)迭代器具有__next __()方法返回一个值,该更新的状态中,并且提出了StopIteration异常时完成。

3)迭代器本身有一个__iter __()方法返回自我。这意味着所有迭代器都是可自我迭代的。

的最后一条规则的用于具有__iter __()方法返回自我迭代器好处是,它可以让我们以绕过部分消耗的迭代器

>>> s = 'hello world' 
>>> it = iter(s) 
>>> next(it) 
'h' 
>>> next(it) 
'e' 
>>> list(it)  # Doesn't start from the beginning 
['l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd'] 

这里的另一个例子取决于迭代器在不重新启动的情况下自迭代:

>>> s = 'hello world' 
>>> it = iter(s) 
>>> list(zip(it, it)) 
[('h', 'e'), ('l', 'l'), ('o', ' '), ('w', 'o'), ('r', 'l')] 

注:

1)的另一种方法,使一个可迭代是提供一种__getitem __()方法接受连续指数和引发IndexError时完成。这是如何在Python 2中迭代对象的str

2)像文件这样的对象是它们自己的迭代器。这意味着您可以直接在文件对象上调用next()。这也意味着文件不能有多个独立的迭代器(文件对象本身具有跟踪文件中的位置的状态)。

3)上述迭代器设计模式不是Python特定的。这是一个用于许多OOP语言的通用设计模式:https://en.wikipedia.org/wiki/Iterator_pattern

相关问题