Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 为什么类需要_iter__;()来返回迭代器?_Python_Python 3.x_Class_Oop_Iterator - Fatal编程技术网

Python 为什么类需要_iter__;()来返回迭代器?

Python 为什么类需要_iter__;()来返回迭代器?,python,python-3.x,class,oop,iterator,Python,Python 3.x,Class,Oop,Iterator,为什么类需要定义返回self的\uuuu iter\uuu()来获得类的迭代器 class MyClass: def __init__(self): self.state = 0 def __next__(self): self.state += 1 if self.state > 4: raise StopIteration return self.state myObj = My

为什么类需要定义返回self的
\uuuu iter\uuu()
来获得类的迭代器

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
答案是,他说

迭代器是具有next(Python 2)或
\uuuuuuuuuuuuuuu
(Python 3)方法的对象

添加以下内容的任务:

def __iter__(self):
   return self
是返回一个迭代器,或类的一个对象,它定义了
\uuuuu next\uuuuu()
方法

但是,当MyClass在myObj=MyClass()行中实例化时,
\uuuuuu new\uuuuuuuuuu()
方法是否已经完成了返回MyClass对象(它定义了
\uuuuuu next\uuuuuuuuuuuuuuuuuuuuuuuuuuu()
方法)的任务

定义
\uuuu next\uuu()
方法的类的对象本身不是迭代器吗

我已经研究了这些问题,但是我仍然无法理解使用
\uu iter\uu()
方法返回self的原因

这不是已经通过
\uuuu new\uuuu()
方法完成了吗

不,
\uuuuuu new\uuuu
只是另一种方法,它不会自动为对象创建
\uuuuuu iter\uuuuu

定义
\uuuu next\uuu()
方法的类的对象本身不是迭代器吗

不一定,正如您的第一个类定义的
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu next\uuuuuuuuuuuuuuuuuuuuu<代码>\uuuuuuuuuuuuuuuuuu如果需要支持迭代,则需要下一步,因为迭代会生成值<代码>\uuuu iter\uuuu
是必需的,因为这是在
for
语句中对对象调用的,以便它获得迭代器

您可以有一个只定义
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。例如,类
MyClass
返回一个类
CustomIter
,该类只定义
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu

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
g = iter(MyClass())

g.__next__() # 0
g.__next__() # 1
您需要在一个对象上定义一个
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
,该对象将返回另一个对象(可能是它本身),该对象上定义了
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu


如果您的类将
\uuuuu iter\uuuu
定义为:

def __iter__(self): return self
然后,您需要在
类型(self)
(类)上定义
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu<代码>\uuuu下一步\uuuu
将在
self
上被调用,直到无法生成更多的值

另一种情况是,
\uuuuu iter\uuuuuuuu
简单地返回另一个对象,该对象定义了
\uuuuuuuuu next\uuuuuuuuu
(如我的第一个示例所示)。您也可以通过将
\uuuuu iter\uuuu
设置为生成器来实现这一点

例如:

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

    def __iter__(self): 
        for i in range(10): yield i
不定义一个
\uuuuuuuuuuuuuuuuuuuuuu
。当对其调用
iter
时,尽管:

g = iter(MyClass())
它返回一个生成器
g
,该生成器定义
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu

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
g = iter(MyClass())

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

为什么有必要使用_iter\u_()方法这个问题的答案是,for循环总是从调用对象上的iter()来获得迭代器开始。这就是为什么即使迭代器本身也需要一个_iter__;()方法来处理for循环。在for调用iter()之后,它会对生成的迭代器调用uu next_uu(),以获得一个值

创建ITerable和迭代器的规则如下:

1) Iterables有一个返回迭代器的_uiter__;()方法

2) 迭代器有一个uuuuuuuuuuuuuuuuuuuuuuuuuuuu next()方法,该方法返回一个值,更新状态,并在完成时引发StopIteration

3) 迭代器本身有一个返回self的_iter__;()方法。这意味着所有迭代器都是可自写的

最后一条规则对于具有返回self的_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) 使iterable的另一种方法是提供一个_getitem__;()方法,该方法接受连续索引,并在完成时引发IndexError。这就是str对象在python2中迭代的方式

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


3) 上面描述的迭代器设计模式不是特定于Python的。这是许多OOP语言的通用设计模式:

我在“这不是已经由
\uuuuu new\uuuuu()
方法完成了吗”中的意思是,当
\uuuu new\uuuuuuu()
方法已经创建了MyClass的对象时,为什么我们需要再次通过
\uuu iter\uuuuuu()
返回MyClass的对象呢,类似于
for
的循环必然调用
\uuuu iter\uuuu()
方法来获取MyClass的实例,或者任何与此相关的类。这就是python中的工作方式吗?如果它存在的话,@thebeliest3。在你的问题正文中的链接中有一些回退选项(例如,如果没有找到
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu;它首先返回调用
\uu iter\uuuuu
的同一个对象,因为该对象的(绑定)
\uuuu next\uuuu
方法是您希望
next
调用的。对于可iterable但本身不是迭代器的类(如
列表
),
\uuuuuuuuuuuuuuuuuu
不返回对象,也不一定返回相同类型的另一个对象。(
list.\uuu iter\uuu
返回类型为
list\u iterator
的全新对象,该对象引用原始列表。)这个问题似乎混淆了迭代器和可迭代器之间的区别。