Python可变对象按引用传参?为何函数内赋值后外部变量未变
为什么Python函数内给参数赋值后,外部变量没变化?
我来帮你理清这个问题——你遇到的是Python参数传递里一个非常常见的误解,直接给你拆解清楚:
先看你的完整代码(整理后)
import pandas as pd a = pd.DataFrame(range(3)) b = pd.DataFrame(range(5)) def change(origin, new): print(id(origin)) print(id(new)) origin = new print(id(origin)) print(id(new)) change(a,b) # 输出: # 559599568 # 559251864 # 559251864 # 559251864 print(a) # 输出: # 0 # 0 0 # 1 1 # 2 2 print(b) # 输出: # 0 # 0 0 # 1 1 # 2 2 # 3 3 # 4 4 print(id(a)) # 559599568L print(id(b)) # 559251864L
核心原因:Python既不是值传递,也不是引用传递,而是「传对象的引用」
你之前的误解是觉得可变对象是按引用传参,但其实Python的参数传递规则是:把外部变量的对象引用,赋值给函数的局部参数变量。
具体到你的代码:
- 调用
change(a,b)时,Python把a指向的DataFrame对象的引用,赋值给函数里的origin;把b的引用赋值给new。这时候origin和a指向同一个对象(所以初始id相同),new和b也是如此。 - 当你执行
origin = new时,你只是修改了**函数内部的局部变量origin**的指向——让它从原来的a的对象,改成指向b的对象。但这个操作完全和外部的a没关系,a还是牢牢指向原来的那个DataFrame。
打个生活化的比方:你和同事手里各有一张纸条,上面写着「会议室A」的地址。你把自己手里的纸条改成「会议室B」,同事手里的纸条还是写着「会议室A」——你们俩的纸条是独立的,只是一开始写的地址一样而已。这里的「纸条」就是变量(a和origin),「地址」就是对象的id。
那如果想让外部的a变成b,该怎么做?
有两种常用方法:
让函数返回新对象,外部重新赋值
这是最清晰、最推荐的方式:def change(origin, new): return new a = change(a, b) # 把函数返回的b的引用重新赋值给a这样操作后,
a就会指向b的对象,id也会变成和b一样。修改可变对象的内部状态,而不是重新赋值变量
因为DataFrame是可变对象,你可以直接修改它的内容,而不是让origin指向新对象:def change(origin, new): origin.clear() # 清空原来的内容 origin.append(new, ignore_index=True) # 把b的内容加进去 change(a, b)这种方式下,
a的id不会变,但它的内容已经变成了b的内容——相当于你没有换纸条,而是直接去会议室A把里面的东西换成了会议室B的。
最后再划个重点
- Python里的变量都是「对象的引用」,不是对象本身。
- 函数参数传递是把引用赋值给局部变量,不是传递变量本身的引用。
- 对函数内的局部参数重新赋值,不会影响外部变量;只有修改可变对象的内部状态,或者外部重新赋值,才能改变外部的结果。
内容的提问来源于stack exchange,提问作者Lisa
相关产品推荐
相关产品推荐

