鱼C论坛

 找回密码
 立即注册
查看: 1137|回复: 10

迭代器概念模糊以及__iter__()和__next__()的的疑问

[复制链接]
发表于 2018-4-23 17:36:43 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 Cczhou 于 2018-4-23 19:02 编辑

疑问一来自如下代码1:
  1. >>>a = 'FishC'
  2. >>>it = iter(a)
  3. >>>it
  4. <str_iterator object at 0x0000000002E46160>  #迭代器
  5. >>>next(it)
  6. >>>'F'
  7. >>>next(a)
  8. Traceback (most recent call last):
  9.   File "<pyshell#97>", line 1, in <module>
  10.     next(a)
  11. TypeError: 'str' object is not an iterator
  12. #a不是一个迭代器
复制代码


迭代的概念:
迭代是重复反馈过程的活动,其目的通常是为了逼近所需目标或结果。每一次对过程的重复称为一次“迭代”,而每一次迭代得到的结果会作为下一次迭代的初始值。

我的理解:上面红字部分的实现就是靠重写__next__()实现的,所以一个迭代器之所以为迭代器,是因为他的实例对象具有next()方法,也就是说__next__()的重写才决定了是不是迭代器,__next__()才是迭代器的灵魂。代码中不能执行next(a),a不是迭代器,他只是一个可迭代对象,同理列表,元组,字典。dir(a)后果然没有__next__, dir(it)就有__next__。


疑问二来自如下代码2:
  1. >>> a = 'abc'
  2. >>> it = iter(a)
  3. >>> it2 = iter(it)
  4. >>> for i in a:
  5.         print(i, end='')

  6.         
  7. abc
  8. >>> for i in it:
  9.         print(i ,end = '')

  10.         
  11. abc
  12. >>> for i in it2:
  13.         print(i ,end = '')

  14.         #没有输出
  15. >>>
复制代码

我的理解:既然a不是迭代器,为什么能作为跟迭代器一样在for中使用呢,是因为for本身就支持迭代器和可迭代对象吗?还是因为for的实现是先iter(可迭代对象),我的理解代码3如下:
  1. a = iter(a)
  2. while True:
  3.     try:
  4.         each = next(a)
  5.     except:
  6.         break
  7.     [执行的代码块]
复制代码


但是如果本身是迭代器,如同代码2的it, it2=iter(it)却没有输出了,这是为什么啊



想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2018-4-23 18:39:24 | 显示全部楼层
迭代器 和 可迭代对象 明显就是两个不同的概念。

可迭代对象 说明这个对像是可能迭代的。

迭代器 自身就有迭代功能。

迭代器 也是可迭代的对像

像下面这样。
>>> a = 'abc'
>>> it = iter(a)
>>> next(a)
Traceback (most recent call last):
  File "<pyshell#2>", line 1, in <module>
    next(a)
TypeError: 'str' object is not an iterator
>>> next(it)
'a'
>>> next(it)
'b'
>>> next(it)
'c'

>>> for i in a:
        print(i)

       
a
b
c
>>> for i in iter(a):
        print(i)

       
a
b
c
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-4-23 18:51:36 | 显示全部楼层
ba21 发表于 2018-4-23 18:39
迭代器 和 可迭代对象 明显就是两个不同的概念。

可迭代对象 说明这个对像是可能迭代的。
  1. >>> a = 'abc'
  2. >>> it = iter(a)
  3. >>> it2 = iter(it)
  4. >>> for i in it2:
  5.         print(i ,end = '')

  6.         #没有输出
  7. >>>
复制代码

it2也是可迭代对象,为什么没有输出了呢
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-4-23 18:53:10 | 显示全部楼层
ba21 发表于 2018-4-23 18:39
迭代器 和 可迭代对象 明显就是两个不同的概念。

可迭代对象 说明这个对像是可能迭代的。

刚刚好像代码显示有问题,现在写好了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2018-4-23 19:00:02 | 显示全部楼层
Cczhou 发表于 2018-4-23 18:51
it2也是可迭代对象,为什么没有输出了呢


感觉你是没事找事。
迭代器生成的迭代器对像,迭代完就没了

>>> it = iter(a)
>>> it2 = iter(it)
这样又是何意?

for i in iter(a):
        print(i ,end = '')

for i in it:
        print(i ,end = '')

上面明显也是两个不同的对象。

>>> a = 'abc'
>>> it = iter(a)
>>> it2 = iter(it)
>>> for i in it2:
        print(i ,end = '')

        
abc
>>>
再次运行:
for i in it2: #迭代器生成的迭代器对像,迭代完就没了
        print(i ,end = '')
#肯定没有 输出   
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-4-23 19:14:34 | 显示全部楼层
ba21 发表于 2018-4-23 19:00
感觉你是没事找事。
迭代器生成的迭代器对像,迭代完就没了

>>> a = 'abc' #也是迭代对象
for i in a:
        print(i ,end = '')
为什么可以一直输出呢?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2018-4-23 19:16:28 | 显示全部楼层
Cczhou 发表于 2018-4-23 19:14
>>> a = 'abc' #也是迭代对象
for i in a:
        print(i ,end = '')



迭代器对像
可迭代对像


for i in iter(a):
        print(i ,end = '')

这也可以总是输出吧。不知道你有没有认真看。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-4-23 20:01:52 | 显示全部楼层
ba21 发表于 2018-4-23 19:16
迭代器对像
可迭代对像

刚刚验证了下发现
  1. it == it2
复制代码
, 所以it迭代完了,it2自然也没有东西可迭代了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-4-23 20:35:23 | 显示全部楼层
为了可以next(a)不报错,可以重写下__next__()
  1. class A(str):
  2.         def __init__(self, *arg):
  3.                 self.a = -1
  4.                 super().__init__()
  5.         def __next__(self):
  6.                 self.a += 1
  7.                 if self.a >= len(self):
  8.                         raise StopIteration
  9.                 return self[self.a]
  10. a = A('abc')

  11. >>>next(a)
  12. 'a'
  13. >>>next(a)
  14. 'b'
  15. >>>next(a)
  16. 'c'
  17. >>>next(a)
  18. StopIteration
复制代码
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2018-4-23 21:07:32 | 显示全部楼层
a:可迭代对象
iter(a):迭代器对象(实际上是生成器对象)
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-4-23 23:38:35 | 显示全部楼层
本帖最后由 Cczhou 于 2018-4-23 23:45 编辑
  1. >>> class Fibs:
  2.         def __init__(self, num = 20):
  3.                 self.a = 0
  4.                 self.b = 1
  5.                 self.num = num
  6.         def __iter__(self):
  7.                 print('调用iter...')
  8.                 return self
  9.         def __next__(self):
  10.                 self.a, self.b = self.b, self.a + self.b
  11.                 if self.a > self.num:
  12.                         raise StopIteration
  13.                 return self.a

  14.        
  15. >>> fibs = Fibs()
  16. >>> for i in fibs:
  17.         print(i)

  18.        
  19. 调用iter...
  20. 1
  21. 1
  22. 2
  23. 3
  24. 5
  25. 8
  26. 13
  27. >>> for i in fibs:
  28.         print(i)

  29.        
  30. 调用iter...
  31. >>>
复制代码

第二次输出没有了,那是因为在Fibs类中,对__iter__方法的重写是直接return self,在for循环中触发迭代器,调用iter(),返回可迭代对象,在第一次for中就已经迭代完了。尽管第二次for中也调用了iter(),但是还是同一个对象,因为是直接return self, 所以没有可迭代的了,就没有输出。
  1. >>> class Fibs:
  2.         def __init__(self, num = 20):
  3.                 self.a = 0
  4.                 self.b = 1
  5.                 self.num = num
  6.         def __iter__(self):
  7.                 print('调用iter...')
  8.                 return self
  9.         def __next__(self):
  10.                 self.a, self.b = self.b, self.a + self.b
  11.                 if self.a > self.num:
  12.                         raise StopIteration
  13.                 return self.a

  14. >>> fibs = Fibs()
  15. >>> a = iter(fibs)
  16. 调用iter...
  17. >>> a
  18. <__main__.Fibs object at 0x00000000030E3630>
  19. >>> b = iter(fibs)
  20. 调用iter...
  21. >>> b
  22. <__main__.Fibs object at 0x00000000030E3630>
  23. >>>
复制代码

若想实现反复输出,则要返回不在一个地址的对象才行
  1. >>> import copy
  2. >>> class Fibs:
  3.         def __init__(self, num = 20):
  4.                 self.a = 0
  5.                 self.b = 1
  6.                 self.num = num
  7.         def __iter__(self):
  8.                 print('调用iter...')
  9.                 tem = copy.copy(self)
  10.                 return tem
  11.         def __next__(self):
  12.                 self.a, self.b = self.b, self.a + self.b
  13.                 if self.a > self.num:
  14.                         raise StopIteration
  15.                 return self.a

  16.        
  17. >>> fibs = Fibs()
  18. >>> for i in fibs:
  19.         print(i)

  20.        
  21. 调用iter...
  22. 1
  23. 1
  24. 2
  25. 3
  26. 5
  27. 8
  28. 13
  29. >>> for i in fibs:
  30.         print(i)

  31.        
  32. 调用iter...
  33. 1
  34. 1
  35. 2
  36. 3
  37. 5
  38. 8
  39. 13
复制代码

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-4-20 06:47

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表