迭代器,生成器

迭代器

迭代器:迭代的工具。迭代是更新换代,迭代也可以说成是重复,并且每一次的重复都是基于上一次的结果来的。如计算机中的迭代开发,就是基于软件的上一个版本更新。以下代码就不是迭代,它只是单纯的重复。

# 纯粹的重复
while True:
    print('我只是一个重复的过程')

可迭代的对象

可迭代对象:只要具有 _inter_ 方法的数据类型,都是可迭代对象。

# 字符串
st = 'zkim'
print(st.__iter__())

# 列表
l = [1,2,3]
print(l.__iter__())

# 元组
t = (1,2,3)
print(t.__iter__())

# 字典
d = {'name':'zkim','age':18}
print(d.__iter__())

# 集合
se = {1,2,3}
print(se.__iter__())

# 文件
f = open('xxx','w',encoding='utf-8')
print(f.__iter__())
f.close()
# <str_iterator object at 0x000000B2AC1EC3C8>
# <list_iterator object at 0x000000B2AC1EC358>
# <tuple_iterator object at 0x000000B2AC1EC390>
# <dict_keyiterator object at 0x000000B2AC1585E8>
# <set_iterator object at 0x000000B2AC1E9BD0>
# <_io.TextIOWrapper name='xxx' mode='w' encoding='utf-8'>

可迭代对象使用 _iter_ 的方法,可以拿到一个返回值,这个返回值就是迭代器对象。

迭代器对象

数据类型中,字符串,列表,元祖都是依赖索引取值的。在这里我们又学到了一个可以不依赖索引,就能取值的方法。(迭代器对象)

迭代器对象:既有内置 _inter_ 方法,又有内置 _next_ 方法的数据类型。

注意:当某一个数据类型中的值,依次被取完之后,如果再取的话就会报错。错误:StopIteration

# 文件类型的数据既有__iter__,又有__next__,所以文件本身就是迭代器对象。
f = open('text.txt','r',encoding='utf-8')
f.__iter__()
f.__next__()
# 字符串
st = 'zkim'
res = st.__iter__()
print(res.__next__())
print(res.__next__())

# 列表
l = [1,2,3]
res1 = l.__iter__()
print(res1.__next__())
print(res1.__next__())

# 元祖
t = (1,2,3)
res2 = t.__iter__()
print(res2.__next__())
print(res2.__next__())

# 字典
d = {'name':'zkim','age':18}
res3 = d.__iter__()
print(res3.__next__())
print(res3.__next__())

# 集合
se = {1,2,3}
res4 = se.__iter__()
print(res4.__next__())
print(res4.__next__())
# z
# k

# 1
# 2

# 1
# 2

# name
# age

# 1
# 2

注意:当某一个数据类型中的值,依次被取完之后,如果再取的话就会报错。错误:StopIteration

l = [1,2]
res = l.__iter__()
print(res.__next__())
print(res.__next__())
print(res.__next__())
# StopIteration

在上述的方法中没取一个值就得 _next_ 一次,特别的繁琐,所以我们可以用 while 循环来精简下。为了防止报错可以使用异常捕捉: try...except... 来处理

l = [1,2,3]
iter_l = l.__iter__()
while True:
    try:
        print(iter_l.__next__())
	except StopIteration:
		break
# 1
# 2
# 3
  • 总结:

迭代器对象:执行可迭代对象的 _inter_ 方法,拿到的返回值就是迭代器对象。

  • 特点:

1:内置 _next_ 方法,执行该方法会拿到迭代器对象中的一个值。

2:内置有 _iter_ 方法,执行该方法会拿到迭代器对象。

3:文件本身就是迭代器对象。

  • 优点:

1:不依赖索引取值。

2:内存中永远只占一份空间,不会导致内存溢出。

  • 缺点:

1:取值麻烦,不能获取指定的值,并且只能往后取。

2:取完之后会报 StopIteration 的错误。

for 循环内部原理

for 循环称之为迭代器循环, in 后面接的必须是可迭代对象。

  • for 循环内部的本质:

1:将 in 后的对象调用 _iter_ 转换成迭代器对象

2:调用 _next_ 迭代取值

3:内部有异常捕获 StopIteration,当 _next_ 报这个粗时,会自动结束循环。

l = [1,2,3]
for i in l:  
    print(i)
# 1
# 2
# 3

生成器

生成器:用户自定义的迭代器,本质就是迭代器。

  • 关键字 yield

1:帮你提供了一种自定义生成器的方式。

2:可以将函数体代码的运行暂停。

3:可以返回值

# 自定义的迭代器:生成器,是定义在函数内部的,利用 yield 关键字,将函数自定义成一个生成器
def func():
    print('我是第一个')
    yield 1
    print('我是第二个')
    yield 2
g = func()  # 在调用函数的时候,有 yield 的情况下不会执行函数体代码
print(g.__next__())  # 执行到 yield 1 的时候暂停
print(g.__next__())  # 执行到 yield 2 的时候暂停
# 只有在调用的时候才会依次往下执行。
# 我是第一个
# 1
# 我是第二个
# 2
# yield 可以接收外部的值
def shopping(shop):
    print('%s 已被购买'%shop)
    while True:
        people = yield
        print('%s 被 %s 购买'%(shop,people))

res = shopping('法拉利')
res.__next__()
res.send('鸡哥')
# 法拉利 已被购买
# 法拉利 被 鸡哥 购买 
  • 与 return 的异同之处

相同点:

都可以返回值,并且都可以返回多个值。

不同点:

yield 可以返回多次值,而 return 只能返回一次后函数立即结束。

yield 还可以接受外部传入的值。

生成器表达式
res = (i for i in range(1,3) if i != 4)
print(res)
print(res.__next__())
print(res.__next__())
# <generator object <genexpr> at 0x0000000BA3EAB728>
# 1
# 2
posted @ 2019-07-15 18:33  光吃葡萄皮  阅读(147)  评论(0编辑  收藏  举报
回顶部