2者不是一回事(废话)
比如
from collections.abc import Iterable,Iterator
print(isinstance([1, 2], Iterable)) # True 列表是可迭代对象
print(isinstance([1, 2], Iterator)) # False 但不是迭代器
能够逐一返回其成员项的对象。
简单说,可迭代对象就是能提供迭代器的任意对象
可迭代对象的例子包括所有序列类型 (例如 list
, str
和 tuple
) 以及某些非序列类型例如 dict
, 文件对象 以及定义了 __iter__()
方法或是实现了 序列 语义的 __getitem__()
方法的任意自定义类对象。
当一个可迭代对象作为参数传给内置函数 iter()
时,它会返回该对象的迭代器。这种迭代器适用于对值集合的一次性遍历。在使用可迭代对象时,你通常不需要调用 iter()
或者自己处理迭代器对象。for
语句会为你自动处理那些操作,创建一个临时的未命名变量用来在循环期间保存迭代器。参见 iterator、sequence 以及 generator。
稍作解释
from collections.abc import Iterable, Iterator
f = open(r'd:\1.jpg', 'rb')
for _ in ([1, ], (1,), '1', {1: 1}, {1}, f):
assert isinstance(_, Iterable), f'{_}不是可迭代对象iterable'
else:
print('都是可迭代对象iterable')
实现_iter_
from collections.abc import Iterable, Iterator
class A:
def __iter__(self):
pass # 实际你肯定不是这样写的
print(isinstance(A(),Iterable)) # True
print(isinstance(A(),Iterator)) # False 注意 , 是Iterable但不是Iterator
实现_getitem_,不符预期
from collections.abc import Iterable, Iterator
class A:
def __init__(self):
self.elements = [1, 2, 3]
def __getitem__(self, i):
return self.elements[i]
a = A()
print(isinstance(a, Iterable)) # 此处是False的,但下面都是ok的
print(a[0])
for i in a:
print(i)
# 所以,https://www.liaoxuefeng.com/wiki/1016959663602400/1017323698112640
# 中提到的“凡是可作用于for循环的对象都是Iterable类型” 这句话是不够准确的
# 但多数情况是OK的
iter()
时,它会返回该对象的迭代器from collections.abc import Iterable, Iterator
list1 = [1,2,3]
it = iter(list1) # 得到了list对象的迭代器
print(type(it)) # <class 'list_iterator'>
print(isinstance(it,Iterable)) # True
print(isinstance(it,Iterator)) # True
for _ in it:
print(_)
s1 = 'abc'
d1 = {1:1}
set1 = {1}
it_s1 = iter(s1)
it_d1 = iter(d1)
it_set1 = iter(set1)
print(type(it_s1)) # str_iterator
print(type(it_d1)) # dict_keyiterator 注意此处,是key的iterator
print(type(it_set1)) # set_iterator
__next__()
方法(或将其传给内置函数 next()
)将逐个返回流中的项。当没有数据可用时则将引发 StopIteration
异常。到这时迭代器对象中的数据项已耗尽,继续调用其 __next__()
方法只会再次引发 StopIteration
异常。__iter__()
方法用来返回该迭代器对象自身,因此迭代器必定也是可迭代对象,可被用于其他可迭代对象适用的大部分场合。一个显著的例外是那些会多次重复访问迭代项的代码。list
)在你每次向其传入 iter()
函数或是在 for
循环中使用它时都会产生一个新的迭代器。如果在此情况下你尝试用迭代器则会返回在之前迭代过程中被耗尽的同一迭代器对象,使其看起来就像是一个空容器。__iter__()
的要求稍作解释
迭代器必定也是可迭代对象
当前命题的反面
关于next()
list1 = [1,2,3]
print(next(list1)) # TypeError: 'list' object is not an iterator
list1 = [1,2,3]
it_list1 = iter(list1)
print(next(it_list1)) # 1
print(next(it_list1)) # 2
print(next(it_list1)) # 3
print(next(it_list1)) # StopIteration
list1 = [1,2,3]
it_list1 = iter(list1)
print(it_list1.__next__()) # 跟刚才调用next是一样的效果
# 所以说__next__这种魔术方法的背后往往有一个内置函数(比如len)、运算符(比如>)、操作(比如下标)与之对应
for循环的本质:通过iter获取可迭代对象后,不断的在调用next()
list1 = [1,2,3]
for _ in list1:
print(_)
print('----华丽的分割线-----')
it_list1 = iter(list1)
while 1:
try:
print(next(it_list1))
except StopIteration:
print('到头了')
break
# for定义
for_stmt ::= "for" target_list "in" expression_list ":" suite
["else" ":" suite]
for
语句用于对序列(例如字符串、元组或列表)或其他可迭代对象中的元素进行迭代:为何list不是iterator呢?
迭代器iterator
__iter__:返回迭代器对象本身
__next__:从容器中返回下一项,必须要有它,确保在next()作用下可以得到下一项
可迭代对象iterable
不是迭代器(2者是有区别的!!)
如果一个对象能生成迭代器,那么它就会被称作 iterable
for .. in 后面的这个玩意必须是一个iterable(好像跟上面冲突了?其他不然)
iterable更像是一个数据的保存者,一个container,它是可以没有状态的,它可以完全不知道你这个iterator数到哪里了,但它需要有能力能产生一个iterator
需要有以下之一
__iter__:
__getitem__:需要是个sequence
可以有东西既是iterable又是iterator的
# https://www.bilibili.com/video/BV1ca411t7A9
# 参考码农高天的示例,稍作更改
from collections.abc import Iterator, Iterable
class Node:
"""
Iterable
"""
def __init__(self, name):
self.name = name
self.next = None
def __iter__(self):
return NodeIterator(self)
class NodeIterator:
def __init__(self, node):
self.current_node = node
def __next__(self):
if self.current_node is None:
raise StopIteration
node, self.current_node = self.current_node, self.current_node.next
return node
def __iter__(self):
return self
node1 = Node('node1')
node1_iterator = NodeIterator(node1)
print(isinstance(node1, Iterable)) # T
print(isinstance(node1_iterator, Iterable)) # T
print(isinstance(node1, Iterator)) # F
print(isinstance(node1_iterator, Iterator)) # T
node2 = Node('node2')
node3 = Node('node3')
node1.next = node2
node2.next = node3
for n in node1:
print(n.name) # 依次输出node1 node2 node3