Python迭代器与索引

时间:2018-01-12 03:23:57

标签: python indexing iterator

当我编写一个函数时,当我尝试两种方法时,我发现了一些有趣的东西。一种方法使用索引,另一种使用迭代器:

索引方法:

A = [1,1,1,1]

def flipBits(A):
  for i in range(len(A)):
      if A[i] == 1: 
          A[i] = 0
      else: 
          A[i] = 1
  return A

>>> flipBits(A)
[0, 0, 0, 0]

迭代器方法:

A = [1,1,1,1]

def flipBits(A):
  for bit in A:
      if bit == 1: 
          bit = 0
      else: 
          bit = 1
  return A

>>> flipBits(A)
[1, 1, 1, 1]

如果我没有弄错,迭代器只是指向某些数据的指针的副本。因此,当我尝试将位设置为某个位置时,它只设置副本,而不是列表的实际元素。

这是对的吗?还有什么我应该知道的吗?感谢。

2 个答案:

答案 0 :(得分:2)

  

如果我没有弄错,迭代器只是指向某些数据的指针的副本。

这是正确的,但并非完全如此。主要的困惑是您没有直接处理第二个代码块中的任何迭代器。 正在使用的迭代器(在for循环内),并且对某些数据有一个引用(换句话说就是指针),但它们并不是同一个东西。 bit变量仅获取迭代器对产生的值的引用。它不是迭代器本身。

您可以编写自己的for循环版本,显式处理迭代器。您没有for bit in A:,而是拥有:

_iterator = iter(A)
while True:
    try:
        bit = next(_iterator)
    except StopIteration:
        break

    # body of the for loop goes here!

del _iterator

请注意bit在循环的每个循环中分配其值。如果您稍后重新分配它(在原始循环的主体中),原始值或它来自的列表都不会被修改。

您可以在第一个代码的略微修改版本中看到类似的事情:

def flipBits(A):
  for i in range(len(A)):
      bit = A[i]
      if bit == 1: 
          bit = 0
      else: 
          bit = 1
  return A

此版本不会修改A,原因与代码的for循环版本没有相同。重新绑定bit(这是一个局部变量)与重新绑定A[i]不同,即使它们都是对相同值的引用。

请注意,如果您不需要来修改A,那么更多的" Pythonic"解决这个问题的方法是使用列表解析创建一个包含翻转位的新列表:

def flipBits(A):
    return [1-bit for bit in A] # you could also use "0 if bit == 1 else 1" instead of 1-bit

答案 1 :(得分:1)

当您使用for循环时,您将创建一个新的引用变量,该变量依次设置为序列中的每个对象。

当您使用=时,它会将左侧的引用设置为右侧的对象。

在第一种情况下,A[i]是对列表元素的直接引用,因此列表会更新。

在第二种情况下,b是与列表分开的引用;它是由for循环创建的。更新它不会改变原始列表。