假设我有一个函数f(),它接受一个列表并返回该列表的变异。如果我想将该函数应用于我的类实例(i)中的五个成员变量,则可以这样做:
for x in [i.a, i.b, i.c, i.d, i.e]:
x[:] = f(x)
1) 有没有更优雅的方式?我不想让f()修改传递的列表。
2) 如果我的变量保存的是简单的整数(无法使用切片表示法),是否也有一种方法?(在这种情况下,f() 还将采用 & 返回一个整数)
另一个解决方案,虽然可能不够优雅:
for x in ['a', 'b', 'c', 'd', 'e']:
setattr(i, x, f(getattr(i, x)))
Python没有按引用传递的功能。最好的方法是编写一个函数来构建一个新列表,并将函数的结果赋值给原始列表。示例:
def double_list(x):
return [item * 2 for item in x]
nums = [1, 2, 3, 4]
nums = double_list(nums) # now [2, 4, 6, 8]
nums = map(lambda x: x * 2, nums)
最终,您想要做的与Python的结构方式不兼容。如果您的变量是列表,则已经有了最优雅的方法来处理,但是对于数字则不可能。
这是因为在Python中不存在变量,只存在引用。所以i.x不是一个列表,而是一个指向列表的引用。同样,它也可以引用一个数字。因此,如果i.x引用了y,那么i.x = z实际上并不会改变值y,而是会改变i.x指向的内存位置。
大多数情况下,变量被视为包含值的盒子。名称在盒子上。在Python中,值是基本的,而“变量”只是标记,用于标识特定的值。一旦习惯了这种方式,就会感觉非常好。
在列表的情况下,您可以使用分片赋值,就像您已经在做的那样。这将允许所有引用列表的地方看到更改,因为您正在更改列表对象本身。对于数字的情况,则无法这样做,因为在Python中,数字是不可变的对象。这是有道理的。五就是五,你不能做太多改变它的事情。如果您知道或可以确定属性的名称,则可以使用setattr
进行修改,但这不会更改可能已经存在的其他引用。
正如Rafe Kettler所说,如果您可以更具体地说明您实际想要做什么,那么我们可以想出一个简单而优雅的方法来实现它。
setattr
就是唯一的方法了。因为你现在使用切片赋值的方式,其他引用将会引用修改后的列表。我同意,虽然它很丑陋。关于你尝试做什么的更多细节会得到更好的答案 ;) - aaronasterling
f
所期望的是一个列表,但你同时在遍历这个列表。 - Michael J. Barber