Python 总是使用传递引用值。也不例外。任何变量赋值都意味着赋值参考值。没有例外。任何变量都是绑定到引用值的名称。总是。
您可以将引用视为在使用时自动取消引用的目标对象的地址。这样,您似乎可以直接使用目标对象。但中间总有一个引用,多一步跳转到目标。
更新 -- 这是一个证明通过引用传递的通缉示例:
如果参数是按值传递的,则无法修改外部lst。绿色是目标对象(黑色是里面存储的值,红色是对象类型),黄色是里面有引用值的内存——如箭头所示。蓝色实心箭头是传递给函数的参考值(通过蓝色虚线箭头路径)。丑陋的深黄色是内部字典。 (实际上也可以画成绿色椭圆。颜色和形状只说它是内部的。)
更新 -- 与 fgb 关于通过引用传递示例 swap(a, b) 的评论和 delnan 关于不可能编写 swap 的评论有关。
在编译语言中,变量是能够捕获类型值的内存空间。在 Python 中,变量是绑定到引用变量的名称(内部捕获为字符串),该引用变量保存目标对象的引用值。变量的名称是内部字典中的键,该字典项的值部分存储对目标的引用值。
swap在其他语言中的作用是交换传递变量的内容,即交换内存空间的内容。这也适用于 Python,但仅限于可以修改的变量——这意味着可以修改其内存空间的内容。这仅适用于可修改的容器类型。从这个意义上说,一个简单的变量始终是常量,即使它的名称可以用于其他目的。
如果函数应该创建一些新对象,那么将其获取到外部的唯一方法是或通过容器类型参数,或通过 Python return 命令。但是,Python return 在语法上看起来好像可以传递多个参数。实际上,外部传递的多个值形成一个元组,但元组可以在语法上分配给更多外部 Python 变量。
更新与其他语言所感知的变量模拟相关。内存空间由单元素列表模拟——即多一层间接。然后swap(a, b) 可以像其他语言一样编写。唯一奇怪的是,我们必须使用列表的元素作为对模拟变量值的引用。必须以这种方式模拟其他语言变量的原因是只有容器(它们的一个子集)是 Python 中唯一可以修改的对象:
>>> def swap(a, b):
... x = a[0]
... a[0] = b[0]
... b[0] = x
...
>>> var1 = ['content1']
>>> var2 = ['content2']
>>> var1
['content1']
>>> var2
['content2']
>>> id(var1)
35956296L
>>> id(var2)
35957064L
>>> swap(var1, var2)
>>> var1
['content2']
>>> var2
['content1']
>>> id(var1)
35956296L
>>> id(var2)
35957064L
请注意,现在var1 和var2 模拟了经典语言中“正常”变量的外观。 swap 更改了它们的内容,但地址保持不变。
对于可修改的对象——例如列表——你可以写出与其他语言完全相同的swap(a, b):
>>> def swap(a, b):
... x = a[:]
... a[:] = b[:]
... b[:] = x[:]
...
>>> lst1 = ['a1', 'b1', 'c1']
>>> lst2 = ['a2', 'b2', 'c2']
>>> lst1
['a1', 'b1', 'c1']
>>> lst2
['a2', 'b2', 'c2']
>>> id(lst1)
35957320L
>>> id(lst2)
35873160L
>>> swap(lst1, lst2)
>>> lst1
['a2', 'b2', 'c2']
>>> lst2
['a1', 'b1', 'c1']
>>> id(lst1)
35957320L
>>> id(lst2)
35873160L
请注意,多重赋值如a[:] = b[:]必须用于表示复制列表的内容。