【问题标题】:Python - How does the index in the __next__() method work?Python - __next__() 方法中的索引如何工作?
【发布时间】:2018-12-31 12:45:38
【问题描述】:

有人可以向我解释__iter__()__next__() 函数如何处理索引吗?它们是基础0 还是基础1

我一直在玩它,但我想知道 Python 在后端实际上做了什么。我尝试了下面的示例类:

>>> class my_class:
        def __init__(self, *stuff):
            self.__stuff = stuff

        def __iter__(self):
            self.__n = 0
            return iter(self.__stuff)

        def __next__(self):
            if self.__n <= len(self.__stuff):
                self.__n += 1
                return self.__stuff(self.__n)
            else:
                raise StopIteration

>>> x = my_class(1, 2, 3, 4)
>>> for each in x:
        print(each)
1
2
3
4

除非我弄错了,__next__() 使用的第一个 self.__n 值应该是 1应该产生,这是:

>>> for each in x:
        print(each)
2
3
4

我错过了什么?它怎么知道从self.__stuff[0]开始?

【问题讨论】:

  • 这里有一些混淆。首先,您通常希望可迭代类型返回另一个专用迭代器类型的实例。所以,iter([1,2,3]) 返回一个 list_iterator 对象。其次,您对__iter__ 的实现只是委托给self.__stuff,在这种情况下它始终是一个元组,因此您的__next__ 方法永远不会出现。最后,不要使用双下划线名称修饰,除非您想要 双下划线名称修饰。按照惯例,私有变量是单下划线。
  • 抱歉,我应该提供更多背景信息。这是因为我正在处理一个项目,其中我的类有很多相互依赖的计算属性值,因此,我尝试使用大量封装。

标签: python list iterator iteration next


【解决方案1】:
  • 当你使用my_class时,它首先调用__init__,然后调用__iter__,最后是__next__
  • 在你的代码中,当它调用__iter__,它return iter(self.__stuff),然后结束,__next__没有被调用。所以输出就是你所看到的。
  • 如果你想调用__next__,你可以像这样改变你的代码(这里__next__使用的self.__n从1开始):

    class my_class:
        def __init__(self, *stuff):
          self.__stuff = stuff
    
        def __iter__(self):
          self.__n = 0
          print('__iter__ is called')
          return self
    
        def __next__(self):
          print('__next__ is called')
          if self.__n <= len(self.__stuff):
              self.__n += 1
              return self.__stuff(self.__n)
          else:
              raise StopIteration
    
  • 提示:您可以使用print 帮助您了解代码在做什么,例如上面代码中的print 函数。

【讨论】:

  • 啊,好吧。我想我的印象是在类中包含__iter__() 方法需要__next__() 方法。对于我的应用程序,我什至不需要它。但是,如果我确实需要它,看起来我只是错误地调用了索引,应该将__next__() 上的return 包含为return self.__stuff[self.__n]。对吗?
  • 你是对的。在这种情况下,__next()__ 不是必需的。
【解决方案2】:

当您调用 for each in x: 时,它不会对您的类定义中的 __next__() 执行任何操作,因此它从您的对象属性的 1 而不是 2 开始。

即使你想调用类似print(next(x)) 的东西,它也会给你'TypeError:'tuple' object is not callable',因为self.__stuff(self.__n) 是无效的,因为self.__stuff 是一个元组,self.__n 是一个整数。您只能拨打tuple[int] 而不是tuple(int)

在您的代码提到之后尝试以下代码,它将返回您想要的输出然后引发异常。

for each in x:    
    print(next(x))

结果:

2
3
4
raise StopIteration

【讨论】:

  • 我正要输入类似的内容,并建议通过在 def next
  • self.__stuff(self.__n) 不是无效语法。它调用 self.__stuff 返回的任何内容,这可能会引发类型错误,因为它不可调用,但 syntax 很好。
  • @ juanpa.arrivillaga,确实是类型错误。改变了,先生。
  • 啊,所以我应该将它声明为self.__stuff = list(stuff) 以便它使用__next__() 方法?
  • @AndyPerez 不,要使其使用__next__ 方法然后__iter__ 必须简单地return self 因为迭代器是必需的 i> 做。但您可能只想要一个 iterable,而不是 iterator
【解决方案3】:

__iter__() 方法返回 iter(self.__stuff) 而不是 self。因此,传递给__init__() 的元组被迭代,而不是对象。

【讨论】:

    猜你喜欢
    • 2019-05-09
    • 2011-08-24
    • 2012-09-15
    • 2019-02-02
    • 1970-01-01
    • 2016-04-25
    • 2013-12-23
    • 2012-04-24
    相关资源
    最近更新 更多