python 为什么可迭代对象不是迭代器?

wmtdaxz3  于 2023-01-24  发布在  Python
关注(0)|答案(6)|浏览(164)

下面是我的代码:

from collections import deque

class linehistory:
    def __init__(self, lines, histlen=3):
        self.lines = lines
        self.history = deque(maxlen=histlen)

    def __iter__(self):
        for lineno, line in enumerate(self.lines,1):
            self.history.append((lineno, line))
            yield line

    def clear(self):
        self.history.clear()

f = open('somefile.txt')
lines = linehistory(f)
next(lines)

错误:

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
    TypeError: 'linehistory' object is not an iterator

我不知道为什么linehistory对象不是迭代器,因为它已经在the类中包含了__iter__方法。

ig9co6j1

ig9co6j11#

迭代的概念在Python文档中有详细的说明。
简言之,“iterable”是提供了我想要迭代的项的对象。它要么已经包含了这些项,那么它也被称为容器。它可以是一个列表、一个字符串、一个元组或任何其他由零到多个项组成的对象。但它也可以是一个产生项的对象。例如itertools中包含的许多类之一,它有__iter__()返回一个迭代器。
一个“迭代器”是用于一次迭代的对象。它可以被看作是一种“游标”。它有next()(在Python 2中)或__next__()(在Python 3中),它们被反复调用,直到它引发一个StopIteration异常。由于任何迭代器都是可迭代的(作为它自己的迭代器),它也有__iter__(),它返回自己。
你可以用iter(obj)得到任何可迭代对象的迭代器。
在你的例子中,linehistory(应该写成LineHistory)是可迭代的,因为它有一个.__iter__()。用它创建的生成器对象是一个迭代器(和每个生成器对象一样)。

neskvpey

neskvpey2#

实际上

    • 所有其他答案都是错误的**(除了@glglgl,他的写作风格很迟钝)。如果使用for循环调用生成器函数__iter__(),它将按原样工作,如下所示
for line in lines:
    print(line)

但是因为使用了next(lines),所以必须首先使用iter()来获取迭代器(我假设它只是对对象调用__iter__()),如下所示

it = iter(lines)
print(next(it))

正如比兹利先生所指出的

uidvcgyl

uidvcgyl3#

我不知道为什么linehistory对象不是迭代器,因为它已经在类中包含了__iter__方法。
错误。请参阅迭代器类型:
迭代器对象本身需要支持以下两个方法,这两个方法共同构成了迭代器协议:
iterator.__iter__()
返回迭代器对象本身。这是允许容器和迭代器都能与for和in语句一起使用所必需的。这个方法对应于Python/C API中Python对象类型结构的tp_iter槽。
iterator.__next__()
返回容器中的下一项。如果没有更多项,则引发StopIteration异常。该方法对应于Python/C API中Python对象类型结构的tp_iternext槽。
但是您可以迭代lines,这是因为您的__iter__方法是一个生成器函数,请参阅生成器类型:
Python的生成器提供了一种实现迭代器协议的便捷方式。如果一个容器对象的__iter__()方法被实现为生成器,它会自动返回一个提供__iter__()__next__()方法的迭代器对象(技术上讲,是一个生成器对象)。关于生成器的更多信息可以在yield表达式的文档中找到。

plicqrtu

plicqrtu4#

迭代器对象需要一个__iter__方法,但它们也需要实现next
迭代器对象本身需要支持以下两个方法,这两个方法共同构成了迭代器协议:
迭代器.iter()
返回迭代器对象本身。
iterator.next()
从容器中返回下一项。
Python 2.7源代码
在Python 3.x中,这些是函数名:
迭代器.iter()
迭代器.next()
Python 3.x源代码

0s0u357o

0s0u357o5#

你的对象它不是迭代器,就像列表它不是迭代器,而是可迭代的,你可以让它成为迭代器,因为迭代器本身就是一个对象。

help(list)

然后:

|  __iter__(self, /)
 |      Implement iter(self).

假设您有一个列表:

a = [1,2,3]

你试着打电话

next(a)

您将获得:

Traceback (most recent call last):
  File "<pyshell>", line 1, in <module>
TypeError: 'list' object is not an iterator

但是,您可以通过在列表上应用iter()来生成列表的迭代器。

>>> iter_a = iter(a)
>>> print(iter_a)
<list_iterator object at 0x03FE8FB0>

>>> next(iter_a)
1

因此,请对您的代码执行以下操作:

f = open('somefile.txt')
lines = linehistory(f)
lines_iter = lines.__iter__()
print(next(lines_iter))

somefile.txt(我的文件)的第一行:

>>> %Run 'some file iterator.py'
aaaaaaa

现在执行:

>>> dir(lines_iter)

您将看到:

'__iter__', '__le__', '__lt__', '__name__', '__ne__', '__new__', '__next__',

看到了吗?它现在有了一个next方法!

11dmarpk

11dmarpk6#

Python的“类型错误:'list'对象不是迭代器”。若要解决此错误,请将列表传递给iter()函数以获取迭代器,例如my_iterator = iter(my_list)

下面是错误发生的示例。

my_list = ['a', 'b', 'c']

# ⛔️ TypeError: 'list' object is not an iterator
print(next(my_list))

我们尝试将列表用作迭代器,但列表不是迭代器(它们是可迭代的)。
要解决这个错误,请将列表传递给iter()函数以获取一个迭代器。

my_list = ['a', 'b', 'c']

my_iterator = iter(my_list)

print(next(my_iterator)) # 👉️ "a"
print(next(my_iterator)) # 👉️ "b"
print(next(my_iterator)) # 👉️ "c"

函数的作用是:返回一个迭代器。
一个迭代器对象代表一个数据流。每次我们把迭代器传递给next()函数时,就会返回数据流中的下一项。
当迭代器耗尽时,将引发StopIteration异常。

my_list = ['a', 'b', 'c']

my_iterator = iter(my_list)

try:
    print(next(my_iterator))  # 👉️ "a"
    print(next(my_iterator))  # 👉️ "b"
    print(next(my_iterator))  # 👉️ "c"
    print(next(my_iterator))
except StopIteration:
    # 👇️ this runs
    print('iterator is exhausted')

当你在for循环中使用一个列表时,一个迭代器会自动为你创建。

my_list = ['a', 'b', 'c']

for el in my_list:
    print(el)  # 👉️ a, b, c

迭代器需要有一个iter()方法,该方法返回迭代器对象本身。
每个迭代器也是一个可迭代对象,但不是每个可迭代对象都是迭代器。
可迭代对象的例子包括所有的序列类型(list、str、tuple)和一些非序列类型,如dict、file对象和其他定义iter()或getitem()方法的对象。
当一个可迭代对象作为参数传递给iter()函数时,它会返回一个迭代器,但是,通常不需要使用iter()函数,因为for语句会自动为我们做这件事。
当使用for语句或向iter()函数传递可迭代对象时,每次都会创建一个新的迭代器。
另一方面,在迭代器耗尽并显示为空容器之前,只能迭代一次。如果需要检查一个值是否可迭代,请使用try/except语句。
如果传入的值不支持iter()方法或序列协议(getitem()方法),iter()函数将引发TypeError。
如果我们向iter()函数传递一个不可迭代的对象,比如整数,就会运行except代码块。

my_str = 'hello'
# my_str = 1  # raise exception

try:
    my_iterator = iter(my_str)

    for i in my_iterator:
        print(i)  # 👉️ h, e, l, l, o
except TypeError as te:
    print(te)

如果传入的值不支持iter()方法或序列协议(getitem()方法),iter()函数将引发TypeError。
如果我们向iter()函数传递一个不可迭代的对象,比如整数,就会运行except代码块。
参考:https://bobbyhadz.com/blog/python-typeerror-list-object-is-not-an-iterator

相关问题