Python 为什么类需要_iter__;()来返回迭代器?
为什么类需要定义返回self的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
\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
的全新对象,该对象引用原始列表。)这个问题似乎混淆了迭代器和可迭代器之间的区别。