我认为Python
中的foreach样式结构将允许我像C#
中那样更新列表。不是。
经过一番调查,我发现在foreach样式结构的Python
中使用的变量不是引用,而是单独的标量变量,因此我无法使用该变量来更新容器。有没有办法使用foreach样式更新容器?
以下代码演示了我的问题:
inputString = " Type X Widgets , 25, 14.20 , Type Y Widgets , 4 , 1.12 "
inputList = inputString.split(',')
print(inputList) # Now I need to get rid of whitespace on the ends of each element
# The foreach-style does NOT update inputList
for element in inputList:
element = element.strip()
print(element, end=",") # element contains the stripped string as I wanted
print()
print(inputList) # the whitespace on the ends of the elements is still there
# The for-style with subscripts DOES update inputList
for i in range(len(inputList)):
inputList[i] = inputList[i].strip()
print(inputList[i], end=",") # inputList[i] contains the stripped string as I wanted
print()
print(inputList) # it finally contains the stripped strings with no whitespace on the ends
以下是上面的输出:
[' Type X Widgets ', ' 25', ' 14.20 ', ' Type Y Widgets ', ' 4 ', ' 1.12 ']
Type X Widgets,25,14.20,Type Y Widgets,4,1.12,
[' Type X Widgets ', ' 25', ' 14.20 ', ' Type Y Widgets ', ' 4 ', ' 1.12 ']
Type X Widgets,25,14.20,Type Y Widgets,4,1.12,
['Type X Widgets', '25', '14.20', 'Type Y Widgets', '4', '1.12']
第一个for循环不会更新容器。第二个做。在这种简单的情况下,不必使用下标就没什么了,但是我真的很希望能够在无法使用下标的情况下使用foreach样式来更新更复杂的容器类型。 / p>
我可以在C#
中进行此操作,它是一种非常有用的工具。除了我在第一个循环中尝试过的操作以外,是否可以在Python
中做到这一点? (如果是这样,我想它会涉及使用指针。Python
甚至还有指针吗?)
答案 0 :(得分:2)
也许这不是您想要的,但是一种简单的方法是创建一个新列表,如下所示:
inputList = [
element.strip()
for element in inputList]
这会将新列表分配给相同的变量,替换旧列表(旧列表将在此后的一段时间内被垃圾回收)。
缺点是,这会使使用的内存量增加一倍;完成上述声明后,可以对旧列表进行垃圾回收,但是内存使用量仍然会激增。
答案 1 :(得分:2)
在这种情况下,您不能这样做。那是因为您是将对象重新分配到新引用。
在这样的“ foreach”迭代中:
for element in inputList:
您要遍历列表中元素本身的对象。但是在这种情况下,它是一个str
对象,它是不可变的。即当您尝试分配此行时:
element = element.strip()
您要从原始内容的剥离内容中为 new 对象重新分配 element 。由于它是一个新对象,因此它与inputList
本身无关。
但是,在第二个示例中,您现在基于inputList
遍历索引的列表:
for i in range(len(inputList)):
# range(len(inputList)) -> range(0, 6)
遍历列表时,请注意,您正在重新分配inputList
的特定索引:
inputList[i] = inputList[i].strip()
这会将 new 对象分配回inputList[i]
。它不再是您曾经在列表中拥有的str
对象。
已经说过,在其他用例中,只要对象是可变的,您正在寻找的“ foreach”就可以正常工作 。观察以下示例:
lst = [[] for _ in range(5)]
lst
# [[], [], [], [], []]
for i in lst:
i.append('foo')
lst
# [['foo'], ['foo'], ['foo'], ['foo'], ['foo']]
请注意此处的区别:i
不是重新分配的,而是通过append()
方法直接更改的。为了进一步证明i
是您所期望的直接对象引用,如果我在迭代完成后这样做
i.append('bar')
lst
# [['foo'], ['foo'], ['foo'], ['foo'], ['foo', 'bar']]
id(i)
# 61353816
id(lst[-1])
# 61353816
看看现在如何添加lst
的 last 元素。这是因为i
仍保留引用。 id()
还会显示您所要询问的确定证据。
如果我要这样写迭代:
for i in lst:
i = ['foo']
lst
# [[], [], [], [], []]
id(i)
# 61354112 <-- different obj id
id(lst[-1])
# 61353816
由于您的示例无法使用的相同原因,它不再起作用。因为i
现在已重新分配给新对象,而不是迭代中的直接对象引用。请注意,对象ID有所不同。
答案 2 :(得分:-2)
嗯。在 for循环中,每次迭代期间,您的变量(在您的情况下为 element )将分配给列表中下一个值(对象)的副本,而不是此值(对象)的参考。 (这不是完全正确的,但是您知道我想说的话)。因此,要解决您的项目,您可能可以执行以下操作:
for element in inputList:
inputList[inputList.index(element)] = element.strip()
print(inputList)
请注意,如果列表中有两次相同的元素,则此方法将无效。
希望它有所帮助!