如何在for循环中修改匿名列表的元素?

时间:2018-02-01 12:18:34

标签: python

是否可以遍历我在for语句中定义的列表并修改该列表的原始元素,或者我是否需要该列表的名称/句柄来通过索引访问其值?我知道具有变量名称的列表存在替代方案。

以下代码不会改变a,b和c。

# in each iteration, this assigns item to the value behind a, b, or c
for item in [a, b, c]: 
    # this reassigns item to a new value, but there is no reference to a, b, or c 
    # (which I would like to have).
    item = some_function(item) 

简化示例(最后的实际示例):

a = 1
b = 3
c = 7

for item in [a, b, c]:
    item = item + 1

print("a: {}; b: {}; c: {}".format(a,b,c))

输出:

a: 1; b: 3; c: 7

期望的输出:

a: 2; b: 4; c: 8

在我的实际使用案例中,abc是numpy数组,我想像这样剪切它们的值:

for gradient in [a, b, c]:
    gradient = np.clip(gradient, -max_value, max_value)

结论/答案

感谢valuable input from bruno desthuilliers,我现在可以自己回答这个问题并添加一些解释:

  • 赋值运算符仅将循环变量重新分配给某个新值,并且不会更改原始列表中的元素。关于名称/变量和作业如何在Python中运行的文章很棒,我强烈推荐它:Facts and myths about Python names and values
  • 为了修改列表中的原始项目(要么让它们指向一些新数据或修改它们的数据),必须要么依赖于对数据进行就地操作的方法,要么希望提供由列表中的条目类型(see this helpful example from cricket_007)。
  • 在我的具体用例中,我在numpy.clip方法的可选out参数中找到了最终解决方案:

    for gradient in [a, b, c]:
        np.clip(gradient, -max_value, max_value, out=gradient)
    

    但是,下面提供的答案,基于map()或列表理解,更具普遍性。

非常感谢你的帮助。

2 个答案:

答案 0 :(得分:1)

你不能这样做,因为变量item是在循环体内更新和反弹的变量,并且在迭代后再次变化。列表中的值本身未更新。

你可以用一个类来做这个,所以你有一些对象可以在循环之后引用回来

class Var():
    def __init__(self, x):
        self.x = x
    def incr(self):
        self.x += 1
   def __str__(self):
       return str(self.x)

a = Var(1)
b = Var(3)
c = Var(7)

for item in [a, b, c]:
    item.incr()

print("a: {}; b: {}; c: {}".format(a,b,c))

或者,您正在寻找类似这样的内容

a, b, c = map(lambda x: x+1, [a, b, c]) 

答案 1 :(得分:1)

此:

a, b, c = [np.clip(gradient, -max_value, max_value) for gradient in (a, b, c)]

主要做你想做的事 - 但要注意,引用这些数组的任何其他名称仍会引用原始(未剪辑)值,因为np.clip()会返回一个新数组。

为了深入解释原因和方法,我强烈建议您花些时间阅读并完全理解Ned Batcheler's excellent article on Python's names, values and bindings