如何在 Python 中通过引用传递值?

2023-09-22 01:32:38

Python 中变量的概念与 C 略有不同,C 是具有唯一地址的命名内存位置。 另一方面,在 Python 中,数据对象存储在内存中,变量只是便于访问的标签。这就是为什么Python是一种动态类型语言,其中变量的类型不需要在赋值之前声明,数据决定类型,而不是其他方式(如C/C++)。

>>> x=100
>>> type(x)
<class 'int'>

在这里,一个整数对象 100 存储在内存中,为了方便起见,x给它分配了一个标签(我们称之为变量)。分配给不同对象的同一标签会更改其类型。

>>> x="Hello World"
>>> type(x)
<class 'str'>

其次,Python 解释器为每个对象分配一个唯一标识符。Python 的内置id() function返回此 id,大致相当于一个内存地址。

>>> x=100
>>> id(x)
140717823786336

请注意,如果x分配给另一个变量y,则两者都具有相同的id,这意味着两者都引用内存中的同一对象。

>>> y=x
>>> id(x), id(y)
(140717823786336, 140717823786336)

因此,函数调用中涉及的实际参数和形式参数具有相同的 id 值。

def myfunction(arg):
    print ("value received {} has id {}".format(arg, id(arg)))
x=100
print ("value sent {} has id {}".format(x, id(x)))
myfunction(x)

输出:

value sent 100 has id 140717823786336
value received 100 has id 140717823786336

因此,可以推断,在 Python 中,函数总是通过引用传递变量来调用。这意味着,如果函数修改了从调用环境接收的数据,则修改应反映在原始数据中。然而,这并不总是正确的。

如果实际的参数变量表示不可变的对象,如 int、float、tuple 或字符串,则函数内部的任何修改都将导致创建不同的对象(该对象将是被调用函数的本地对象),并且不会影响原始变量。

def myfunction(arg):
    print ("value received {} has id {}".format(arg, id(arg)))
    arg=arg+10
    print ("value changed {} has id {}".format(arg, id(arg)))
x=100
print ("value sent {} has id {}".format(x, id(x)))
myfunction(x)
print ("value after function call {} has id {}".format(x, id(x)))

输出:

value sent 100 has id 140717823786336
value received 100 has id 140717823786336
value changed 110 has id 140717823786656
value after function call 100 has id 140717823786336

可以看出,递增收到的参数(它是一个不可变的 int 对象)会创建一个新对象(具有不同的 id),并且不会影响引用x的原始对象。

相反,如果将可变对象(如列表)传递给函数,则函数内部的修改将在函数调用后反映,如以下函数所示。

def myfunction(arg):
    print ("list received {} has id {}".format(arg, id(arg)))
    arg.append(40)
    print ("list changed {} has id {}".format(arg, id(arg)))
x=[10,20,30]
print ("list sent {} has id {}".format(x, id(x)))
myfunction(x)
print ("list after function call {} has id {}".format(x, id(x)))

输出:

list sent [10, 20, 30] has id 1864061271048
list received [10, 20, 30] has id 1864061271048
list changed [10, 20, 30, 40] has id 1864061271048
list after function call [10, 20, 30, 40] has id 1864061271048

最后,我们可以得出结论,即使任何对象通过引用传递给函数,函数的更改也只反映在可变对象的情况下,而不是在不可变对象的情况下。