python 可迭代对象是什么_Python 可迭代对象,迭代器,生成器

楔子假如我现在有一个列表l=['a','b','c','d','e'],我想取列表中的内容,有几种方式?

首先,我可以通过索引取值l[0],其次我们是不是还可以用for循环来取值呀?

你有没有仔细思考过,用索引取值和for循环取值是有着微妙区别的。

如果用索引取值,你可以取到任意位置的值,前提是你要知道这个值在什么位置。

如果用for循环来取值,我们把每一个值都取到,不需要关心每一个值的位置,因为只能顺序的取值,并不能跳过任何一个直接去取其他位置的值。

但你有没有想过,我们为什么可以使用for循环来取值?

for循环内部是怎么工作的呢?

一、python中的for循环

要了解for循环是怎么回事儿,咱们还是要从代码的角度出发。

首先,我们对一个列表进行for循环。

for i in [1,2,3,4]:

print(i)

上面这段代码肯定是没有问题的,但是我们换一种情况,来循环一个数字1234试试

for i in 1234

print(i)

结果:

Traceback (most recent call last):

File "test.py", line 4, in

for i in 1234:

TypeError: 'int' object is not iterable

看,报错了!报了什么错呢?“TypeError: 'int' object is not iterable”,说int类型不是一个iterable,那这个iterable是个啥?

1.什么叫迭代

现在,我们已经获得了一个新线索,有一个叫做“可迭代的”概念。

首先,我们从报错来分析,好像之所以1234不可以for循环,是因为它不可迭代。那么如果“可迭代”,就应该可以被for循环了。

这个我们知道呀,字符串、列表、元组、字典、集合都可以被for循环,说明他们都是可迭代的。

我们怎么来证明这一点呢?

from collections import Iterable

l = [1,2,3,4]

t = (1,2,3,4)

d = {1:2,3:4}

s = {1,2,3,4}

print(isinstance(l,Iterable))

print(isinstance(t,Iterable))

print(isinstance(d,Iterable))

print(isinstance(s,Iterable))

结合我们使用for循环取值的现象,再从字面上理解一下,其实迭代就是我们刚刚说的,可以将某个数据集内的数据“一个挨着一个的取出来”,就叫做迭代。

2.可迭代协议

我们现在是从结果分析原因,能被for循环的就是“可迭代的”,但是如果正着想,for怎么知道谁是可迭代的呢?

假如我们自己写了一个数据类型,希望这个数据类型里的东西也可以使用for被一个一个的取出来,那我们就必须满足for的要求。这个要求就叫做“协议”。

可以被迭代要满足的要求就叫做可迭代协议。可迭代协议的定义非常简单,就是内部实现了__iter__方法。

接下来我们就来验证一下:

print(dir([1,2]))

print(dir((2,3)))

print(dir({1:2}))

print(dir({1,2}))

['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']

['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'count', 'index']

['__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'clear', 'copy', 'fromkeys', 'get', 'items', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values']

['__and__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__iand__', '__init__', '__ior__', '__isub__', '__iter__', '__ixor__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__or__', '__rand__', '__reduce__', '__reduce_ex__', '__repr__', '__ror__', '__rsub__', '__rxor__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__xor__', 'add', 'clear', 'copy', 'difference', 'difference_update', 'discard', 'intersection', 'intersection_update', 'isdisjoint', 'issubset', 'issuperset', 'pop', 'remove', 'symmetric_difference', 'symmetric_difference_update', 'union', 'update']

总结一下我们现在所知道的:可以被for循环的都是可迭代的,要想可迭代,内部必须有一个__iter__方法。

接着分析,__iter__方法做了什么事情呢?

print([1,2].__iter__())

结果

执行了list([1,2])的__iter__方法,我们好像得到了一个list_iterator,现在我们又得到了一个新名词——iterator。

iterator,这里给我们标出来了,是一个计算机中的专属名词,叫做迭代器。

3.迭代器协议

既什么叫“可迭代”之后,又一个历史新难题,什么叫“迭代器”?

'''

dir([1,2].__iter__())是列表迭代器中实现的所有方法,dir([1,2])是列表中实现的所有方法,都是以列表的形式返回给我们的,为了看的更清楚,我们分别把他们转换成集合,

然后取差集。

'''

#print(dir([1,2].__iter__()))

#print(dir([1,2]))

print(set(dir([1,2].__iter__()))-set(dir([1,2])))

结果:

{'__length_hint__', '__next__', '__setstate__'}

我们看到在列表迭代器中多了三个方法,那么这三个方法都分别做了什么事呢?

iter_l = [1,2,3,4,5,6].__iter__()

#获取迭代器中元素的长度

print(iter_l.__length_hint__())

#根据索引值指定从哪里开始迭代

print('*',iter_l.__setstate__(4))

#一个一个的取值

print('**',iter_l.__next__())

print('***',iter_l.__next__())

证明在for循环中,就是在内部调用了__next__方法才能取到一个一个的值。

那么 可迭代对象与迭代器定义:可迭代对象包含迭代器。

如果一个对象拥有__iter__方法,其是可迭代对象;如果一个对象拥有next方法,其是迭代器。

定义可迭代对象,必须实现__iter__方法;定义迭代器,必须实现__iter__和next方法。

4.什么是生成器Generator

本质:迭代器(所以自带了__iter__方法和__next__方法,不需要我们去实现)

特点:惰性运算,开发者自定义

5.生成器实现生成器函数:也是用def定义的,利用关键字yield一次性返回一个结果,阻塞,重新开始

生成器表达式:返回一个对象,这个对象只有在需要的时候才产生结果

生成器函数

"""

第一是直接作为脚本执行,

第二是import到其他的python脚本中被调用(模块重用)执行。

因此if __name__ == '__main__': 的作用就是控制这两种情况执行代码的过程,

在if __name__ == '__main__':下的代码只有在第一种情况下(即文件作为脚本直接执行)才会被执行,而import到其他脚本中是不会被执行的。

"""

def myYield(n):

while n>0:

print('开始生成。。。')

yield n

print('完成一次。。。')

n -= 1

if __name__ == '__main__':

a = myYield(3)

print('已经实例化生成器对象')

# a.__next__()

# print('第二次调用__next__()方法:')

# a.__next__()

生成器表达式

L = [x + 1 for x in range(10)]

print(L)

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

如果可以公众号加个关注吧!!!!感谢您

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值