如何通过引用传递方式将切片传递给函数

5
如果我有
a = [1, 2, 3]

def foo (arr):
    for i in len (arr): arr [i] += 1

def bar (arr):
    foo (arr[:2])

bar (a)
print (a)

我希望您能输出结果为:
>>> [2, 3, 3 ]

我该如何处理这个问题?

动机:我想要一个优先队列,在其中我可以冻结最后的N个元素,即仅传递queue[:N]heapq.heappush()。但是,每次我将切片传递给它,或者一般地传递给任何函数时,它都会发送一个切片的副本而不是实际的列表到该函数中去,因此我的列表最终保持不变。


你还有另一个问题:for item in arr: item += 1也不会改变列表。 - Jean-François Fabre
将数组切片会创建另一个对象。 - vishes_shell
arr[:2] 的意义是什么,当输出为 [2, 3, 4] 时(对所有元素加1)? - Jean-François Fabre
4个回答

5

如果a是一个numpy数组,这将起作用。默认情况下,numpy切片引用与原始数组相同的内存块。

import numpy as np
a = np.array([1, 2, 3])

def foo(arr):
    for i in range(len(arr)): arr[i] += 1
    # or just arr += 1

def bar(arr):
    foo(arr[:2])

bar(a)
print(a)
# [2, 3, 3 ]

1
使用列表推导式并使用完整切片赋值[:]更新初始列表:
def foo(arr):
   arr[:] = [x+1 for x in arr]

试用:

>>> a = [1, 2, 3]
>>> def foo(arr):
...    arr[:] = [x+1 for x in arr]
...
>>> foo(a)
>>> a
[2, 3, 4]

不错,但我认为它没有解决“切片”问题。我承认:OP的问题不清楚,但看看def bar(arr):foo(arr[:2])。我认为这样做是不行的。 - Jean-François Fabre
我认为另一个函数并没有反映出问题的目标。我看到他们所期望的输出已经清楚地说明了。 - Moses Koledoye

1
说实话,与其使用切片,我宁愿直接传递索引值;
a = [1, 2, 3]
def foo(array, start, stop, jmp= 1):
    for idx in range(start, stop + 1, jmp):
        array[idx] += 1

def bar(array):
    foo(array, 1, 2)
bar(a)
print(a)
[1, 3, 4]

0

对列表进行切片将创建一个包含切片内容的新列表,因此arr[:2]会失去对原始a的引用。

除此之外,像你这样迭代不会改变列表,它只会更改一个item并忽略其值。

如果您想要更改列表的特定部分,则必须携带对原始列表的引用。例如,保留arr,使用enumerate(arr[:2])迭代其中一部分,然后更改arr

a = [1, 2, 3]

def foo(arr):
    for i, item in enumerate(arr[:2]): 
        arr[i] = item + 1

def bar(arr):
    foo(arr)

bar(a)
print(a)

现在打印的是[2, 3, 3],如果在enumerate中删除切片,则结果为[2, 3, 4]。当然,在这里bar没有任何作用,您可以将其删除并仅保留foo,然后立即调用foo(a)


@Jean-FrançoisFabre 如果第二个问题是如何传递一个切片并保持原始引用,那么按照他想要的方式是不可能的。您可以在迭代过程中进行切片以获得类似的结果(如果这是他想要的)。 - Dimitris Fasarakis Hilliard

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接