Python 与国际热核实验堆(iter)合作,但不是下一个

Python 与国际热核实验堆(iter)合作,但不是下一个,python,iterator,language-lawyer,Python,Iterator,Language Lawyer,对于迭代器协议,您可以创建一个\uuuuu iter\uuuuu和\uuuu next\uuuu方法。但是,以下情况如何: class Item: def __init__(self): self.name = 'James' def __iter__(self): return self 现在我可以做: >>> i=Item() >>> iter(i) <__main__.Item instance a

对于迭代器协议,您可以创建一个
\uuuuu iter\uuuuu
\uuuu next\uuuu
方法。但是,以下情况如何:

class Item:
    def __init__(self):
        self.name = 'James'
    def __iter__(self):
        return self
现在我可以做:

>>> i=Item()
>>> iter(i)
<__main__.Item instance at 0x10bfe6e18>
注意,这将是定义了迭代器方法的完整类:

class Item:
    def __init__(self):
        self.name = 'James'
        self.i = 0
    def __iter__(self):
        return self
    def __next__(self):
        if self.i >= len(self.name): raise StopIteration
        value = self.name[self.i]
        self.i += 1
        return value
这是否意味着我上面的项是一个Iterable而不是迭代器

没有;要使iterable可用,
\uuuuuuu iter\uuuu
方法应返回迭代器。你的没有

根据官方Python文档中的描述:

Iterable

一种能够一次返回一个成员的对象。iterables的示例包括所有序列类型(如
list
str
tuple
)和一些非序列类型,如
dict
、文件对象以及使用实现序列语义的
\uuuuuuuuuuuuuuuuuuuuuuuu item()
方法定义的任何类的对象

Iterables可以在
for
循环中使用,也可以在需要序列的许多其他地方使用(
zip()
map()
,…)

由于您的项目不能“一次返回一个成员”,并且不能“在<代码>循环[或]需要序列的其他地方使用”,因此它不适用

还要注意的是,
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
方法不足以成为迭代器;迭代器还必须具有
\uuuu iter\uuu
方法:

迭代器对象也需要实现这个方法;他们必须自己返回


你的定义基本上是正确的,但不完全正确

  • 如果对象具有返回迭代器的
    \uuuuuuuuuuuuuuuuuu
    方法,则该对象是可迭代的
  • 如果对象在迭代时有一个
    \uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
    方法来获取下一个值,那么它就是迭代器。但是Python中的迭代器也应该是可移植的。它们都应该有一个返回self的
    iter
    方法
您的第一个示例有一个
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
方法,但由于它返回
self
,并且对象不是迭代器(因为它没有
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu

要使非迭代器iterable,您需要返回其他有效迭代器的对象。一种偷偷摸摸的方法是将
\uuuu iter\uuuu
作为一种生成器方法(通过在其实现中使用
yield
)。但是,如果要返回一些值序列,也可以只返回该序列上的迭代器

最后一个代码块中的类实际上是一个迭代器。但是,如果您想使它成为一个iterable,而不是它自己的迭代器(可能是因为您希望能够对它进行多次迭代),那么您可能需要类似以下内容:

class Item:
    def __init__(self):
        self.name = 'James'
    def __iter__(self):
        return iter(self.name)

\uuuu iter\uuuu
\uuuu next\uuuu
作为iterable和iterator是不同的东西。虽然可以在同一个类上同时使用两个方法,
\uuuu iter\uuuu
返回
self
,但这只适用于概念验证,不适用于生产代码

一个iterable将有一个
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuu
方法,该方法返回一个对象,该对象具有
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。如果两个实例与中的相同

这只是一个演示,代码有错误


类别项目:
定义初始化(自身,数据):
self.data=数据
定义(自我):
self.counter=0
回归自我
定义下一个(自我):
self.counter+=1
如果self.counter>len(self.data):
提升停止迭代()
返回self.data[self.counter-1]
这将起作用-但是如果您尝试在同一个Item实例上创建两个独立的迭代器,它们将无法按预期工作-因为这两个迭代器将共享同一个计数器-实例中的属性
counter

然而,很少有人需要实现
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。Python将调用自动创建的生成器上的
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu

这很有效


类别项目:
定义初始化(自身,数据):
self.data=数据
定义(自我):
对于self.data中的项目:
收益项目
正如您所看到的,正确的方法是“无需下一步”且简单得多,在本例中,还可以通过为数据返回独立的迭代器来实现。(如果获得每个项目需要一些自定义计算,则需要实现收益率)

这同样有效


类别项目:
定义初始化(自身,数据):
self.data=数据
定义(自我):
返回iter(自我数据)
(在这种情况下,Python将在为
self.data
创建的迭代器上调用
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu

如果您确实想要实现
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
,那么使用该方法的对象必须跟踪检索下一项所需的任何计数器或指针,并且必须独立于主机实例。最直接的方法是使用与第一个类相关的第二个类,并让
返回该类的实例:

工作“完整”示例


类别项目:
定义初始化(自身,数据):
self.data=数据
定义(自我):
返回项迭代器(self)
类项迭代器:
定义初始(自身,项目):
self.item=项目
self.counter=0
定义下一个(自我):
self.counter+=1
如果self.counter>len(self.item.data):
提升停止迭代()
返回self.item.data[self.counter-1]

这门课的内容被打破了。我明白了,谢谢你的详尽回答。换句话说,如果我执行
def\uu iter\uuuu(self):返回iter(self.name)
,那么它将是一个iter,对吗[
class Item:
    def __init__(self):
        self.name = 'James'
        self.i = 0
    def __iter__(self):
        return self
    def __next__(self):
        if self.i >= len(self.name): raise StopIteration
        value = self.name[self.i]
        self.i += 1
        return value
class Item:
    def __init__(self):
        self.name = 'James'
    def __iter__(self):
        return iter(self.name)