今天我们来聊聊一个新手容易混淆的问题,Python的引用传递。相信用过Java、C++的人在使用python传参时,总会有些困惑,明明写的是传引用,但是结果和预期不一样。其实这个问题我们需要先搞清楚一个问题:Python的变量机制,从根上就和其它的语言不一样。pass by reference的核心逻辑是给函数传递的是原始变量的内存地址,函数内部对参数做的任何操作,都会直接影响到外部的原始变量。值传递的逻辑和引用传递完全相反,它给函数传递的不是原始变量,而是原始变量的副本,函数内部操作的是副本,不论如何修改,都不会改变原始变量的值:def function(int_val): int_val += 100 # 操作的是副本 print("函数内部的值:", int_val)int_val = 100print("调用函数前:", int_val)function(int_val)print("调用函数后:", int_val)
调用函数前: 100函数内部的值: 200调用函数后: 100
def function(list_val): list_val.append('B') # 操作的是原始对象(通过内存地址) print("函数内部的列表:", list_val)list_val = ['A']print("调用函数前:", list_val)function(list_val)print("调用函数后:", list_val)
调用函数前: ['A']函数内部的列表: ['A', 'B']调用函数后: ['A', 'B']
我们传递的列表list_val = ['A'],函数内部给列表添加了元素B,外部的原始列表也跟着变了,因为这里传递的是列表的内存地址,函数操作的是原始对象本身。为什么Python会这样呢?因为Python中万物皆对象,不管是int、str这样的基础类型,还是list、dict这样的复杂类型,本质上是对象,而每个对象都有三个核心属性,我们可以用python内置函数,直接查看这三个属性:# 定义一个列表对象(可变对象)list_val = [1, 2, 3]# 1. 查看身份(内存地址):用 id() 函数print(id(list_val)) # 输出示例:3578332784044(每个人的输出会不一样)# 2. 查看类型:用 type() 函数print(type(list_val)) # 输出:<class 'list'># 3. 查看内容:直接打印对象print(list_val) # 输出:[1, 2, 3]
Python函数传参时,传递的永远是对象的引用,但最终是否会修改原始对象,取决于对象是否可变:不可变对象 int、str、tuple,无法修改对象本身,函数内部看似可以修改,其实是创建了一个新对象,所以原始对象不变;可变对象list、dict、set可以直接修改对象的内容,函数内部通过引用操作原始对象,所以原始对象会被改变。其实很多新手踩坑,都是因为把 Python 的变量机制,和 Java、C++ 的变量机制混为一谈了——Python 没有“变量声明”,变量只是“对象的标签”,而不是“内存容器”。搞懂这一点,不仅能明白传参逻辑,后续学习赋值、深浅拷贝时,也会轻松很多。