Python 中函数参数是值传递还是引用传递?

Python 的参数传递是"对象引用传递":可变对象(列表/字典)在函数内修改会影响外部,不可变对象(数字/字符串)不会。本文详解原理和注意事项。

最佳实践
Python 中函数参数是值传递还是引用传递?封面

Python 既不是纯值传递也不是纯引用传递,而是"对象引用传递"(pass by object reference)。函数接收到的是对象的引用:可变对象(list/dict)在函数内修改会影响外部;不可变对象(int/str/tuple)不会,因为不能原地修改。

不可变对象:函数内修改不影响外部

def modify(x):
    x = x * 2      # 创建新对象,不影响外部
    print(x)        # 10

y = 5
modify(y)
print(y)            # 5(没变)

x = x * 2 创建了新的 int 对象,x 指向新对象,外部的 y 仍指向原来的 5。

可变对象:函数内修改影响外部

def modify(lst):
    lst.append(4)   # 原地修改,影响外部
    print(lst)       # [1, 2, 3, 4]

my_list = [1, 2, 3]
modify(my_list)
print(my_list)       # [1, 2, 3, 4](被修改了!)

append() 是原地修改,同一个列表对象被函数和外部共享。

常见踩坑:默认参数

# 危险!默认参数是可变对象
def add_item(item, target=[]):
    target.append(item)
    return target

add_item(1)  # [1]
add_item(2)  # [1, 2]——上次的列表被复用了!

# 正确写法
def add_item(item, target=None):
    if target is None:
        target = []
    target.append(item)
    return target

如何避免函数修改原始数据

def safe_modify(lst):
    new_lst = lst.copy()   # 创建副本
    new_lst.append(4)
    return new_lst

original = [1, 2, 3]
result = safe_modify(original)
print(original)  # [1, 2, 3](未被修改)
print(result)    # [1, 2, 3, 4]

常见问题(FAQ)

Q:如何判断一个对象是不是可变的?
A:可变:list、dict、set、bytearray;不可变:int、float、str、tuple、frozenset。也可以看有没有 __hash__——不可变对象通常可哈希。

Q:函数内重新赋值会影响外部吗?
A:不会。x = 新值 只是让局部变量指向新对象,外部的变量不受影响。只有调用可变对象的原地修改方法(append/extend/pop 等)才影响外部。

Q:tuple 里的 list 能修改吗?
A:能。tuple 不可变是指不能增删元素,但如果元素是 list,这个 list 本身可以被修改。这是深浅拷贝需要注意的地方。

获取专属方案

联系我们

加入社区

微信扫码
加入官方交流群

立即体验

在线开通,按量计费,真正的云服务!

立即开始

选择观测云版本

代码托管平台