Python函数参数传递方式:值传递vs引用传递
Python 函数参数传递方式常被分为值传递和引用传递。这两种方式都是用来描述在函数调用中传递参数的方式。本篇文章将主要介绍这两个概念的含义和在Python中的应用。
1. 值传递(Pass by Value)
在值传递中,函数调用时,将实际参数的值(变量的值)复制一份传递给形式参数。在函数代码内部接收的参数是该值的一份副本,函数对该副本的任何改变都不会影响到实际参数的值。
在 Python 中,所有的数据类型都是值传递,即使传递的是对象,也是传递对象的引用 (所谓引用,就是一个指向内存中对象地址的指针)的值。不过需要注意的是,字符串、数字和元组等不可变类型的值传递在传递较大数据时,其时间和空间效率是非常高的。
例如:
def my_func(x):
x = 5
print("my_func 中 x 的值为:", x)
y = 10
my_func(y)
print("函数执行后 y 的值为:", y)
输出结果为:
my_func 中 x 的值为: 5 函数执行后 y 的值为: 10
在上述代码中,函数将 y 的值复制一份,并用这个副本去执行函数,而不会改变 y 本身的值。
2. 引用传递(Pass by Reference)
在引用传递中,函数调用时,将实际参数的地址传递给形式参数。在函数代码内部接收的参数是该地址所指向的对象,函数对该对象的任何改变都会影响到实际参数的值。
在Python中,列表、字典等可变类型是通过引用传递的,实际是传递了地址的引用。因为这些对象具有可变性,所以在函数内部对它们的操作可能会影响实参。
例如:
def my_func(lst):
lst[0] = 5
print("my_func 中 lst 的值为:", lst)
lst1 = [1, 2, 3]
my_func(lst1)
print("函数执行后 lst1 的值为:", lst1)
输出结果为:
my_func 中 lst 的值为: [5, 2, 3] 函数执行后 lst1 的值为: [5, 2, 3]
在上述代码中,函数接收 lst1 的地址,在代码内部对其进行操作,这导致实参 lst1 的值也发生了变化。
3. 传递不可变对象和可变对象
在Python 中,如何理解哪些对象可以修改,哪些对象不能修改是一个非常重要的问题。不可变对象是那些一旦创建就不能再被修改的对象,例如字符串、数字和元组等,而可变对象则是那些可以添加、删除或者修改元素的对象,例如列表和字典等。
对于传递不可变对象,虽然也是传递的引用值,但是操作这些值并不会影响到实际参数的值。
例如:
def my_func(s):
s = s + ' world'
print("my_func 中 s 的值为:", s)
str1 = 'hello'
my_func(str1)
print("函数执行后 str1 的值为:", str1)
输出结果为:
my_func 中 s 的值为: hello world 函数执行后 str1 的值为: hello
在上述代码中,my_func中连接字符串后的值是一个新的对象,虽然也是通过传递地址的引用去改变它,但是因为不可变对象,所以实际参数 str1 的值并未发生变化,函数内部操作只对传递过来的参数产生了影响。
对于传递可变对象,函数对其进行的任何修改都会影响实际参数的值。
例如:
def my_func(lst):
lst.append(4)
print("my_func 中 lst 的值为:", lst)
lst1 = [1, 2, 3]
my_func(lst1)
print("函数执行后 lst1 的值为:", lst1)
输出结果为:
my_func 中 lst 的值为: [1, 2, 3, 4] 函数执行后 lst1 的值为: [1, 2, 3, 4]
在上述代码中,函数操作了一个可变对象,因此实际参数 lst1 的值发生了改变。
总结
Python中的函数参数传递可以分为值传递和引用传递两种方式。对于可变对象,由于其具有可变性,因此在函数内部对其进行的任何修改都会影响实际参数的值。对于不可变对象,虽然也是通过传递引用值进行传递,但是操作其并不会改变实际参数的值。在实际开发中,需要注意业务需求,合理选择参数传递方式,以此避免潜在的Bug问题。
