Python可迭代(Iterable)、迭代器(Iterator)和生成器(Generator)

可迭代对象 Iterable

可迭代对象(Iterable):一个对象只要实现了__iter__()方法,那么用isinstance()函数检查就Iterable对象。

例如:

class IteraObj:
	def __iter__(self):
		# 这里简单地返回自身
        # 但实际情况可能不会这么写
        # 而是通过内置的可迭代对象来实现
        # 下文的列子中将会展示
		return self

it = IterObj()
print(isinstance(it, Iterable))  # true
print(isinstance(it, Iterator))  # false
print(isinstance(it, Generator)) # false

常见的可迭代对象:

  1. 集合或序列类型,如list, tuple, set, dict, str
  2. 文件对象;
  3. 在类中定义 __iter__() 方法的对象;

自定义的Iterable对象,要满足在 for 循环中正确使用,必须保证 __iter__() 方法正确实现(可以通过内置 iter()函数将其转换成Iterator对象)。

  1. 在类中只定义 __getiem__() 方法的对象,可以通过 iter() 函数转化成 Iterator 对象。即 一个对象能够在 for 循环中运行, 但不一定是Iterable对象。

首先验证1,2

具体如下:

# 1. 
from collections import Iterable, Iterator
print(isinstance([], Iterable)) # true   list是可迭代的  
print(isinstance({}, Iterable)) # true   dict是可迭代的
print(isinstance((), Iterable)) # true   tuple是可迭代的
print(isinstance(set(),  Iterable)) # true  set是可迭代的
print(isinstance('', Iterable)) # true  str是可迭代的

print(isinstance([], Iterator))  # False  
print(isinstance({}, Iterator))  # False  
print(isinstance((), Iterator)) # False  
print(isinstance(set(),  Iterator))  # False  
print(isinstance('', Iterator)) # False  

# 2.
cur_path = os.path.dirname(os.path.abspath(__file__))
with open(cur_path + '/model.py') as f:
	print(isinstance(f, Iterable))  # true
	print(isinstance(f, Iterator))  # true

# 3.
print(hasattr([], '__iter__'))  # true
print(hasattr({}, '__iter__'))  # true
print(hasattr((), '__iter__'))  # true
print(hasattr('', '__iter__'))  # true

结论:集合和序列对象是可迭代的但不是迭代器。

这些内置集合或序列对象都含有 __iter__属性,是Iterable对象。但它们要在 for 循环中被使用,就应该能够被内置的 iter() 函数调用并转化成 Iterator 对象。

例如:

print(iter([])) # 
print(iter({})) # 
print(iter(())) # 
print(iter('')) # 

这些内置集合或序列为Iterable对象, 都可以转换为对应的 Iterator对象。

其次验证3

再回头修改自定的 IterObj

class IterObj:
	def __init__(self):
		self.a = [3, 5, 7, 11, 13, 17, 19]
	
	def __iter__(self):
		return iter(self.a)

it = IterObj()
print(isinstance(it, Iterable)) # true
print(isinstance(it, Iterator)) # false
print(isinstance(it, Generator)) # false
print(iter(it)) # 
for i in it:
    print(i) # 将打印3、5、7、11、13、17、19元素

结论:在定义一个Iterable对象是,要注意__iter__() 方法的内部实现逻辑, 一般情况下,利用一些已知的 Iterable对象(如集合、序列、文件等或其他正确定义的Iterable对象)来辅助我们实现。

最后验证4
iter()函数可以将一个实现了 __getitem__() 方法的对象转换成Iterator对象,但他不是 Iterable对象。

例子:

class IterObj:
    
    def __init__(self):
        self.a = [3, 5, 7, 11, 13, 17, 19]
    
    def __getitem__(self, i):
        return self.a[i]
        
it = IterObj()
print(isinstance(it, Iterable)) # false
print(isinstance(it, Iterator)) # false
print(isinstance(it, Generator)) false
print(hasattr(it, "__iter__")) # false
print(iter(it)) # 

for i in it:
    print(i) # 将打印出3、5、7、11、13、17、19

结论:可以在 for 中使用的对象,不一定是可迭代对象。

综上所述

  1. 一个 Iterable 对象是实现了 __iter__() 方法的对象;
  2. 它要在 for 中循环使用,就必须满足 iter() 的调用(即调用这个函数不会出错,能正确转成一个 Iterator 对象)
  3. 可以通过已知的 Iterable 对象来辅助实现我们自定义的Iterable 对象。
  4. 一个对象实现了 __getiem__() 方法, 可以通过 iter() 函数转换成 Iterator 对象,即可以在 for 循环中使用,但它不是一个Iterable 对象。

迭代器 Iterator

定义: 一个对象实现__iter__()__next__()两个方法,那么它就是一个Iterator对象。
作用: 遍历集合元素。注意:只能从开头顺序访问至结尾。
特点:

  1. 迭代器:一个可以记住遍历位置的对象。→ 节省内容
  2. 迭代器:有两个基本方法:iter()next()
  3. 可迭代对象:可通过iter()方法构建迭代器。
form collections import Iterable, Iterator

l = [1,2,3,4,5] 
print(isinstance(l, Iterable))  # True 可迭代对象
print(isinstance(l, Iterator))  # False 不是迭代器 

it = iter(l)   # 创建迭代器对象
print(isinstance(it, Iterable))  # True 可迭代对象
print(isinstance(it, Iterator))  # False 不是迭代器 

#  1. next() 顺序遍历迭代器
print(next(it), end=" ")  

#2. for() 循环遍历迭代器
for x in it:   
   print(x)
  1. 自定义迭代器
  • __iter__() 方法 → 起始位置
  • __next__() 方法 → 下一个,终止位置
from collections import Iterable, Iterator
# 构建一个可以反向输出的列表可迭代对象
class listDemo(object):
    def __init__(self):
        self.__data = []
        self.__num = 0

    def __iter__(self):
        return self

    def __next__(self):
        if self.__num <= 0:
            raise StopIteration  # 终止
        else:
            self.__num -= 1
            return self.__data[self.__num]

    def __setitem__(self, key, value):  # 插入
        self.__data.insert(key, value)
        self.__num += 1

    def __getitem__(self, index):  # 读取
        return self.__data[index]

    def __delitem__(self, index):  # 删除
        del self.__data[index]
        self.__num -= 1

    def __len__(self):
        return len(self.__data)

mylist = listDemo()
mylist[0], mylist[1], mylist[2], mylist[3] = '1', '2', '3', '4'
print('Iterable:', isinstance(mylist, Iterable))
print('Iterator:', isinstance(mylist, Iterator))

# 法1: 无需iter(), 因为该对象已为迭代器对象
print(next(mylist))
print(next(mylist))

# 法2: 从当前迭代器位置 for循环
for i in mylist:
    print(i, end=" ")

del mylist[2]
print(len(mylist))
print(type(mylist))

斐波那契迭代器
相关知识

class Fibonacci():  # 定义迭代器类
    def __init__(self):
        self.a = 0
        self.b = 1
        
    def __iter__(self):
        return self
        
    def __next__(self):
        if self.b > 100:
            raise StopIteration      # 结束条件
        else:
        	self.a, self.b = self.b, self.a + self.b
        return self.a
        
fib = Fibonacci()  # 实例化迭代器对象

# for 循环
for f in fib:
    print(f, end=' ')

生成器

方式:

  1. 列表生成器 → 节省内存
  2. 使用·yield·定义生成器

特点:
一个生成器对象既是可迭代对象,也是迭代器对象。

验证方式1

from collections import Iterator, Iterable, Generator
g = (x * 2 for x in range(10))  # 0~18的偶数生成器
print(isinstance(g, Iterable))  # true
print(isinstance(g, Iterator))  # true
print(isinstance(g, Generator))  # true
print(hasattr(g, "__iter__"))  # true
print(hasattr(g, "__next__"))  # true

print(next(g))  # 0
print(next(g))  # 2

for x in g:
    print(x, end=' ')

验证方式2

  1. yield的作用相当于return,可通过next()函数或for循环遍历。
  2. 程序执行遇到yield关键字,生成函数返回当前值,继续向下执行。
def gen():
	for i in range(5):
		print('before')
		yield i  # 生成器函数
		print('after')
	print('end')
	
it = gen()
print(list(it)) # 直接将生成器能生成的所有值存储成列表或者元组的形式

it2 = gen()
print(next(it2))
print(it2.__next__())

it3 = gen()
for i in it3:
	print(i, end=" ")

容器

Python容器

参考资料

一文彻底搞懂Python可迭代(Iterable)、迭代器(Iterator)和生成器(Generator)的概念

你可能感兴趣的:(python,python,开发语言,爬虫)