面试题答案
一键面试按值调用和按引用调用的概念
- 按值调用(Call by value):函数接收的是参数值的副本。在函数内部对参数的修改不会影响到函数外部的原始变量。
- 按引用调用(Call by reference):函数接收的是参数的内存地址(引用),函数内部对参数的修改会直接影响到函数外部的原始变量。
在简单数据类型(整数)上的表现
Python 中整数是不可变类型,虽然 Python 传递参数的方式既不是严格的按值调用也不是按引用调用,但是在处理像整数这样的不可变类型时类似按值调用。
def change_number(num):
num = num + 1
return num
original_num = 5
new_num = change_number(original_num)
print(f"原始值: {original_num}")
print(f"函数内修改后的值: {new_num}")
在上述代码中,original_num
的值在函数调用后并未改变,因为函数 change_number
接收到的是 original_num
值的副本,对副本的修改不影响原始变量。
在复合数据类型(列表)上的表现
列表是可变类型,在 Python 中处理列表时类似按引用调用。
def change_list(lst):
lst.append(4)
return lst
original_list = [1, 2, 3]
new_list = change_list(original_list)
print(f"原始列表: {original_list}")
print(f"函数内修改后的列表: {new_list}")
这里,original_list
在函数调用后被修改了,因为函数 change_list
接收到的是 original_list
的引用,对列表的操作直接影响了原始列表。
性能差异分析
- 简单数据类型(整数):由于是不可变类型且类似按值调用,函数操作的是副本,每次传递和修改不会影响原始数据,在一些情况下,因为不需要考虑数据一致性等问题,性能可能相对稳定。但是如果频繁传递大的不可变对象的副本,会占用较多内存和时间在数据复制上。
- 复合数据类型(列表):类似按引用调用,函数直接操作原始对象,避免了数据复制带来的开销,在处理大型数据结构时,性能优势明显。然而,如果多个地方同时对一个可变对象进行操作,可能需要额外的同步机制来保证数据一致性,这可能会带来一定的性能损耗。