Python:通过引用传递和切片赋值

Posted

技术标签:

【中文标题】Python:通过引用传递和切片赋值【英文标题】:Python: Pass by reference and slice assignment 【发布时间】:2018-01-02 07:10:34 【问题描述】:

在 Python 中,列表是通过引用函数来传递的,对吧?

如果是这样,这里发生了什么?

>>> def f(a):
...     print(a)
...     a = a[:2]
...     print(a)
...
>>> b = [1,2,3]
>>> f(b)
[1, 2, 3]
[1, 2]
>>> print(b)
[1, 2, 3]
>>>

【问题讨论】:

a[:] = a[:2] 是你应该做的。 del a[2:] 也可以,并且更具可读性。 f 接收对列表的引用,而不是对 b 变量的引用;分配给a 不会影响b 变量。虽然 f 是通过引用传递的,但“按引用传递”具有特定含义,不适用于 Python 的参数传递模型。 nedbatchelder.com/text/names.html 是我见过的了解 Python 的这部分工作原理的最佳参考。 【参考方案1】:

在声明中:

a = a[:2]

您正在创建一个新的本地(f())变量,您使用与输入参数a 相同的名称调用该变量。

也就是说,你所做的相当于:

def f(a):
    print(a)
    b = a[:2]
    print(b)

相反,您应该更改a 就地,例如:

def f(a):
    print(a)
    a[:] = a[:2]
    print(a)

【讨论】:

Nitpick:您没有创建新的局部变量/掩盖输入参数。参数是局部变量。您只是在重复使用相同的名称。 @Artyer 你是对的。我对这里的术语有点粗心。编辑将随之而来。谢谢。【参考方案2】:

当你这样做时:

a = a[:2]

它将a 重新分配给一个新值(列表的前两项)。

所有 Python 参数都通过引用传递。您需要更改它所引用的对象,而不是让 a 引用一个新对象。

a[2:] = []
# or
del a[2:]
# or
a[:] = a[:2]

第一个和最后一个分配给列表的切片,就地更改列表(影响其值),中间的也通过删除其余元素来更改列表的值。

【讨论】:

数组切片不是通过引用传递的。 @DavidBandel 如果你在谈论f(a[:2]) 之类的东西,它将“通过引用”评估a[:2] 的结果传递给f。在列表上,这会创建列表某些部分的副本,但这不是重点(Python 没有“按值传递”语义)。例如,f(x := a[:2]); x[0] is a[0] 对于列表可能为 False。 如果你再也不能访问我们的“引用”指向的东西,你怎么能认为它是通过引用传递的呢?我认为它是价值/参考二分法中的灰色区域。【参考方案3】:

确实,对象是通过引用传递的,但a = a[:2] 基本上创建了一个指向列表切片的新局部变量。

要修改列表对象,您可以将其分配给其切片(切片分配)。

考虑ab 等效于您的全局b 和本地a,这里将a 分配给新对象不会影响b

>>> a = b = [1, 2, 3]    
>>> a = a[:2]  # The identifier `a` now points to a new object, nothing changes for `b`.
>>> a, b
([1, 2], [1, 2, 3])
>>> id(a), id(b)
(4370921480, 4369473992)  # `a` now points to a different object

切片分配按预期工作:

>>> a = b = [1, 2, 3]    
>>> a[:] = a[:2]  # Updates the object in-place, hence affects all references.
>>> a, b
([1, 2], [1, 2])
>>> id(a), id(b)
(4370940488, 4370940488)  # Both still point to the same object

相关:What is the difference between slice assignment that slices the whole list and direct assignment?

【讨论】:

以上是关于Python:通过引用传递和切片赋值的主要内容,如果未能解决你的问题,请参考以下文章

Python值传递和引用传递(详细分析)

Python和Java参数传递[重复]

python中的“引用”和C++的引用

python中变量的引用、可变和不可变类型、局部变量和全局变量

01PHP 引用赋值和传递赋值

深浅拷贝