在Python中优雅地通过引用修改变量列表的方式?
假设我有一个函数 f(),它接收一个列表并返回这个列表的一个变种。如果我想把这个函数应用到我类实例 (i) 中的五个成员变量上,我可以这样做:
for x in [i.a, i.b, i.c, i.d, i.e]:
x[:] = f(x)
1) 有没有更优雅的方法?我不想让 f() 修改传入的列表。
2) 如果我的变量是简单的整数(这在切片表示法中是行不通的),有没有其他方法?(在这种情况下,f() 也会接收并返回一个整数)
3 个回答
最终,你想做的事情和Python的结构是不兼容的。如果你的变量是列表,那你已经有了最优雅的做法,但对于数字来说,这就不行了。
这是因为在Python中,变量并不存在,只有引用。所以i.x
并不是一个列表,而是一个指向列表的引用。同样的,如果它指向一个数字也是如此。如果i.x
指向y
,那么当你执行i.x = z
时,并不会改变y
的值,而是改变了i.x
指向的内存位置。
大多数时候,变量被看作是装值的盒子,盒子上有名字。在Python中,值是基本的,而“变量”只是挂在特定值上的标签。习惯了之后,这种方式其实挺不错的。
对于列表,你可以使用切片赋值,就像你现在在做的那样。这会让所有指向这个列表的引用都看到变化,因为你是在改变列表对象本身。对于数字来说,就没有办法做到这一点,因为数字在Python中是不可变的对象。这是有道理的,五就是五,你没法改变它。如果你知道或者能确定属性的名字,那么你可以用setattr
来修改它,但这不会改变已经存在的其他引用。
正如Rafe Kettler所说,如果你能更具体地说明你想做什么,我们就能想出一个简单优雅的方法来实现它。
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 能支持的解决方案。
还有一种解决办法,虽然可能不是特别优雅:
for x in ['a', 'b', 'c', 'd', 'e']:
setattr(i, x, f(getattr(i, x)))