【问题标题】:Built in iter() function and for statement内置 iter() 函数和 for 语句
【发布时间】:2020-08-03 00:16:43
【问题描述】:

我试图了解for x in y 语句在python 中的工作原理。我在这里找到了文档:https://docs.python.org/3/reference/compound_stmts.html#for。它表示表达式 y 被评估一次,并且必须产生一个可迭代的对象。

即使我的类没有实现__iter__(这是我对可迭代的理解),以下代码也会打印数字 1、2、3、4、5。

class myclass:
    def __init__(self):
        self.x = [1,2,3,4,5]
    def __getitem__(self,index):
        return self.x[index]
m = myclass()
for i in m:
    print(i)

我知道有一个内置方法 iter() 使用其 .__getitem__() 函数和从 0 开始的计数器返回序列对象的迭代器。

我的猜测是,python 在 for x in y 语句中的表达式 y 上调用了 iter() 函数。因此,它将实现.__getitem__ 的对象转换为迭代器,并且当我的对象在.__getitem__ 调用期间引发IndexError 异常时,迭代器将其转换为StopIteration 异常,并且for 循环结束。

这是正确的吗?对还是错,这是在文档中的某个地方进行了解释,还是我需要查看实现的源代码?

【问题讨论】:

  • __getitem__() 具有顺序索引,以IndexError 终止,是 Python 迭代器协议的原始版本,可追溯到 Python 1.x 时代。显然,为了向后兼容,它仍然受支持。但是,是的,iter() 函数完全等同于 for 循环对其序列对象所做的操作。
  • @RichieV:列表具有__iter__ 方法的事实实际上完全无关紧要。如果列表没有__iter__,则此代码的行为相同。
  • @jasonharper - 有趣。我对这项工作感到惊讶。我认为这个答案是值得的。

标签: python python-3.x


【解决方案1】:

根据 PEP 234,在上面的 cmets 中有帮助,

iter(obj) 呼叫PyObject_GetIter(obj)

关于 for 循环有以下说法:

为 for 循环生成的 Python 字节码已更改为使用新的操作码 GET_ITERFOR_ITER,它们使用迭代器协议而不是序列协议来获取循环变量的下一个值。这使得可以使用 for 循环来循环支持 tp_iter 槽的非序列对象。解释器循环序列值的其他地方也应更改为使用迭代器。

最后https://docs.python.org/3/library/dis.html#opcode-GET_ITER解释说GET_ITER相当于调用iter

综上所述,for 循环的行为似乎与内置的iter 函数相同。

【讨论】:

    【解决方案2】:

    愉快的 Pythoning。

    getitem 是 Python 2.2 版本之前在迭代器上迭代循环的唯一方法。在 Pyhton 2.2 版本中引入了 iter 方法。在 getitem 方法中,index 自动作为 0 传递,即 0 索引,并且每次循环运行迭代时增加 1。一旦 IndexError 引发,我们就退出循环。具有向后兼容性的 getitem 方法仍未被弃用(直到 Python 版本 3.8.5)。所以现在首先循环搜索 iter 方法在 iterable 中搜索,如果此方法不存在,则搜索 getitem 方法。所以早在 Python 2.2 出现的时候,所以今天的开发者更喜欢使用 iternext 方法,这让人们对可迭代和迭代器有了清晰的理解。

    您可以在您的示例中再举一个 getitem 示例来理解迭代器和迭代器,如下所示。

    class myclass:
        def __init__(self):
            pass
        def __getitem__(self,index):
            return index
    m = myclass()
    for i in m:
        print(i)
    

    上面的代码将创建一个无限循环,因为第一个索引值将是 0,然后是 1,然后是 2,依此类推,不会引发错误。

    以上代码的输出:

    0
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    .
    .
    .
    .
    

    感谢分享问题。

    【讨论】:

      猜你喜欢
      • 2010-09-23
      • 2019-08-22
      • 2021-04-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多