函数/方法中的参数是否通过值或引用传递?

时间:2018-09-28 04:13:19

标签: python

在Python范围内,函数/方法中的参数是否通过值或引用传递?

我已经进行了一些研究,并且有很好的资源:Are integers in Python passed by value or reference?

这个详细的参考可能是非常好的参考,但是主要是关于整数的。 ti如何表示功能/方法的参数

我在命令行中做了一些测试/跟踪:

his_list = [1, 2, 3]
her_list = [4, 5, 6]
def change_list1(mylist):
    mylist.append(100)
    return mylist

def change_list2(mylist):
    mylist = her_list
    return mylist

test_list1 = change_list1(his_list)
test_list2 = change_list2(his_list)
print('test_list1: {}'.format(test_list1))
print('test_list2: {}'.format(test_list2))
print('his_list: {}'.format(his_list))

test_string = change_string(his_string)
print('test_string: {}'.format(test_string))
print('his_string: {}'.format(his_string))

结果是:

test_list1: [1, 2, 3, 100]
test_list2: [4, 5, 6]
his_list: [1, 2, 3, 100]
test_string: abcdef
his_string: abc

如果参数是通过引用传递的,为什么change_list2的结果看起来像是按值传递的?另外,当我将代码放入IDE中时,change_list2中的参数更改为灰色(暗示未使用其值)?

2 个答案:

答案 0 :(得分:2)

Python通过 object 传递。在change_list1中,传递一个可变对象,然后对其进行突变。它是同一对象(一个列表),只是被更改(内容已更改)。 mylist是引用该对象的局部参数。该函数返回原始对象。您还会发现his_list也被更改了,因为它引用了相同的对象。

change_list2中,您还传递了一个可变对象,但没有对它进行突变,而是将一个新对象分配给局部参数。原始对象未更改。该函数返回新对象。

将Python中的变量视为对象名称很有帮助。将参数传递给函数时,函数中的参数名称只是传递给函数的原始对象的新名称。

您可以通过打印传递到函数中的对象名称的ID和参数的对象名称的ID来查看此信息。

a = [1,2,3] # mutable object (content can be altered)
b = 1       # immutable object (content can't be altered).

print(f'id(a) = {id(a)}, id(b) = {id(b)}')

def func(c,d):
    print('INSIDE func')
    print(f'id(c) = {id(c)}, id(d) = {id(d)}')
    c.append(4)  # mutable object can be altered.
    d = 4        # local name 'd' assigned a new object.
    print('AFTER altering c & d')
    print(f'id(c) = {id(c)}, id(d) = {id(d)}')
    return c,d

e,f = func(a,b)

print('AFTER func called')
print(f'id(a) = {id(a)}, id(b) = {id(b)}')
print(f'id(e) = {id(e)}, id(f) = {id(f)}')

print(f'a = {a}, b = {b}')
print(f'e = {e}, f = {f}')

输出:

id(a) = 2290226434440, id(b) = 1400925216
INSIDE func
id(c) = 2290226434440, id(d) = 1400925216
AFTER altering c & d
id(c) = 2290226434440, id(d) = 1400925312
AFTER func called
id(a) = 2290226434440, id(b) = 1400925216
id(e) = 2290226434440, id(f) = 1400925312
a = [1, 2, 3, 4], b = 1
e = [1, 2, 3, 4], f = 4

请注意,ab的ID与参数名称cd一致。这些名称指的是相同的对象。

c对象被突变。 a指向相同的对象,因此将显示相同的更改。

d对象是不可变的。没有像.append这样的方法可以更改对象的内容。 d只能重新分配。它被重新分配并显示一个新的ID。 b对象不变。

函数调用后,e成为名为c(也称为a)的对象的新名称。名称c不再存在。这是一个本地函数名称。 f成为对象d(整数4)的新名称,并且d不再存在。 b不受影响,并引用原始整数1。

ae指的是原始但变异的对象。 bf指的是不同的,不变的对象。

答案 1 :(得分:2)

Python使用一种机制,称为“按对象调用”,有时也称为“按对象引用调用”或“按共享调用”。

如果将不可变的参数(例如整数,字符串或元组)传递给函数,则传递的行为类似于按值调用。对象引用传递给函数参数。它们不能在函数中更改,因为它们根本无法更改,即它们是不可变的。如果传递可变参数,则有所不同。它们也通过对象引用传递,但是可以在函数中对其进行更改。如果我们将列表传递给函数,则必须考虑两种情况:列表元素可以就地更改,即,即使在调用者的范围内,列表也将更改。如果将新列表分配给该名称,则旧列表将不受影响,即,呼叫者范围内的列表将保持不变。

参考:https://www.python-course.eu/passing_arguments.php