Python 函数传参本质是传引用(对象的内存地址),不存在“传值、传指针”,区分在于:不可变对象不能原地修改,可变对象可以原地修改。
不可变类型:int、float、str、bool、tuple、frozenset可变类型:list、dict、set
1. 核心特点
当把不可变对象传给函数:
- 如果函数内部对形参重新赋值,只是让局部变量指向新对象,完全不影响外部实参;
重点:不是“拷贝一份值传进去”,而是对象本身不可改写,赋值只会产生新对象。
2. 示例:int(不可变)
deffunc(num):
print(f"函数内,修改前 id={id(num)}")
num = 100# 重新赋值,num指向新int对象,局部变量
print(f"函数内,修改后 id={id(num)}")
a = 10
print(f"外部实参 id={id(a)}")
func(a)
print(f"外部 a = {a}")
输出
外部实参 id=140xxxx
函数内,修改前 id=140xxxx
函数内,修改后 id=140yyyy
外部 a = 10
num=100:不是修改原来整数,创建新整数对象,局部变量num指向新地址;
3. 字符串 str 示例(不可变)
字符串不支持原地修改,+=会生成新字符串
defchange_str(s):
s += " world"# 生成新字符串对象,局部s指向新对象
print("函数内部:", s)
s1 = "hello"
change_str(s1)
print("外部:", s1)
输出
函数内部: hello world
外部: hello
注意:s += xxx 对不可变类型,等价于 s = s + xxx,是重新赋值。
4. 元组 tuple
元组整体不可变,如果元组里面嵌套可变对象,嵌套的可变对象可以原地修改!这个是高频坑点。
t = (1, [2,3])
defchange_tuple(tp):
tp[1].append(4) # 没有修改元组本身,修改元组内部的list(可变)
change_tuple(t)
print(t) # (1, [2, 3, 4])
- 但元组只是存对象地址,如果里面装list/dict,list可以原地改动。
5. 和可变类型参数做对比(方便理解)
deffunc_list(lst):
lst.append(99) # 原地修改对象,外部会跟着变
my_list = [1,2]
func_list(my_list)
print(my_list) # [1,2,99]
list是可变,append原地修改内存中对象,外部实参看到变化。
6. 总结表格
7. 面试一句话总结
Python全部参数传递都是传递对象引用。不可变类型作为参数,函数内部无法修改原始对象;函数内对形参赋值只会创建新对象,外部变量不受影响。如果元组内部嵌套可变对象,嵌套内容可以被原地修改。