在Python中优雅地通过引用修改变量列表的方式?

4 投票
3 回答
848 浏览
提问于 2025-04-16 10:38

假设我有一个函数 f(),它接收一个列表并返回这个列表的一个变种。如果我想把这个函数应用到我类实例 (i) 中的五个成员变量上,我可以这样做:

for x in [i.a, i.b, i.c, i.d, i.e]:
    x[:] = f(x)

1) 有没有更优雅的方法?我不想让 f() 修改传入的列表。

2) 如果我的变量是简单的整数(这在切片表示法中是行不通的),有没有其他方法?(在这种情况下,f() 也会接收并返回一个整数)

3 个回答

2

最终,你想做的事情和Python的结构是不兼容的。如果你的变量是列表,那你已经有了最优雅的做法,但对于数字来说,这就不行了。

这是因为在Python中,变量并不存在,只有引用。所以i.x并不是一个列表,而是一个指向列表的引用。同样的,如果它指向一个数字也是如此。如果i.x指向y,那么当你执行i.x = z时,并不会改变y的值,而是改变了i.x指向的内存位置。

大多数时候,变量被看作是装值的盒子,盒子上有名字。在Python中,值是基本的,而“变量”只是挂在特定值上的标签。习惯了之后,这种方式其实挺不错的。

对于列表,你可以使用切片赋值,就像你现在在做的那样。这会让所有指向这个列表的引用都看到变化,因为你是在改变列表对象本身。对于数字来说,就没有办法做到这一点,因为数字在Python中是不可变的对象。这是有道理的,五就是五,你没法改变它。如果你知道或者能确定属性的名字,那么你可以用setattr来修改它,但这不会改变已经存在的其他引用

正如Rafe Kettler所说,如果你能更具体地说明你想做什么,我们就能想出一个简单优雅的方法来实现它。

2

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 能支持的解决方案。

4

还有一种解决办法,虽然可能不是特别优雅:

for x in ['a', 'b', 'c', 'd', 'e']:
    setattr(i, x, f(getattr(i, x)))

撰写回答