Python 中的函数参数传递:传值还是传引用? 传参行为

在 Python 中,函数参数传递的方式是很多程序员初学时常常困惑的地方。它与许多编程语言不同,因为 Python 既不完全是“传值调用”,也不完全是“传引用调用”。为了清楚地理解这一点,我们需要明确 Python 中的参数传递机制。

1. Python 参数传递的本质:传对象引用

Python 的函数参数传递方式被称为 “传对象引用”(pass-by-object-reference)或 “传值引用”(pass-by-assignment)。这意味着,当一个对象作为参数传递给函数时,实际上传递的是对象的引用,而不是对象的副本。具体来说,传递的是对象在内存中的地址(即引用),而不是对象本身。通过这种机制,函数可以访问并修改传入的对象,但行为是否改变对象取决于对象的类型(是否是可变类型)。

不同类型的对象:可变与不可变

Python 中的对象可以分为两类:

  1. 不可变对象(Immutable objects):如整数(int)、浮动数(float)、字符串(str)、元组(tuple)等。
  2. 可变对象(Mutable objects):如列表(list)、字典(dict)、集合(set)等。

这些类型的对象在函数调用时有着不同的行为,影响着我们是否能够修改原始对象的值。

2. 不可变对象:传递对象的引用,但不能修改

对于不可变对象,虽然我们传递的是对象的引用,但由于不可变对象的特性,在函数内部修改这些对象的值会导致新的对象的创建,而不会改变原始对象。

示例:
def modify_value(a):
 a = 10 # 创建新的整数对象并赋值给a
x = 5
modify_value(x)
print(x) # 输出 5,原始x值未改变

解释:

  • modify_value 函数中,我们尝试将 a 设置为 10。由于 int 是不可变类型,a 并不会直接修改原始的 x 变量,而是创建了一个新的整数对象 10 并赋值给 a
  • 因此,x 保持不变,输出为 5
为什么不可变对象不能修改?

不可变对象一旦创建,它的值就无法更改。这意味着对于不可变对象,任何改变都相当于创建了一个新的对象,并将引用指向这个新对象。因此,传递给函数的引用指向的对象本身无法改变,但引用可以指向一个新的对象。

3. 可变对象:传递引用并修改原始对象

对于可变对象,函数内部可以通过引用修改对象的内容,因为它们是可变的。这样,对原始对象的修改将影响到外部变量。

示例:
def modify_list(lst):
 lst.append(4) # 修改原始列表对象
my_list = [1, 2, 3]
modify_list(my_list)
print(my_list) # 输出 [1, 2, 3, 4],原始列表被修改

解释:

  • my_list 传递给 modify_list 函数时,lst 指向与 my_list 相同的内存地址。当我们在函数内对 lst 进行 append(4) 操作时,实际上是在修改原始对象。
  • 因此,my_list 被直接修改,输出为 [1, 2, 3, 4]
为什么可变对象会改变?

可变对象的值可以在原地修改。由于传递的是对象的引用,函数对这些对象的操作直接影响原始对象。因此,对于列表、字典等可变对象,函数调用过程中对其内容的修改是可见的。

4. 赋值操作与修改对象

值得注意的是,如果在函数内部重新赋值参数变量(例如 lst = [7, 8, 9]),并不会影响原始对象的引用。这是因为,重新赋值操作会让函数内部的参数变量指向一个新的对象,而不会修改原始对象。

示例:
def modify_reference(lst):
 lst = [7, 8, 9] # 重新赋值,lst指向新的对象
original_list = [1, 2, 3]
modify_reference(original_list)
print(original_list) # 输出 [1, 2, 3]

解释:

  • modify_reference 函数中,lst 被重新赋值为 [7, 8, 9]。这时,lst 不再指向原始的 original_list,而是指向一个新的列表对象。
  • 由于重新赋值仅影响函数内部的 lst 变量,original_list 保持不变。

5. 总结:传对象引用,但行为依赖于对象的类型

  • 不可变对象:当不可变对象(如 int, str, tuple)作为参数传递时,函数内无法修改原始对象。任何修改都会创建新的对象,原始对象保持不变。

  • 可变对象:当可变对象(如 list, dict, set)作为参数传递时,函数内可以修改原始对象的内容,影响外部的变量。如果在函数内重新赋值给参数变量(例如 lst = [...]),则仅会改变函数内的引用,而不会影响外部对象。

结论

Python 中的参数传递是 传对象引用(pass-by-object-reference),但行为依赖于对象的类型。对于不可变对象,传递的引用无法改变对象的内容;而对于可变对象,引用可以直接修改对象的内容。因此,在编写 Python 函数时,理解这一点对于避免意外的副作用和编写高效代码至关重要。

作者:威桑原文地址:https://blog.csdn.net/m0_74091159/article/details/144167398

%s 个评论

要回复文章请先登录注册