Python传递对象参数未被覆盖的疑问:代码对比与传参机制探究
为什么两段Python代码修改参数后原变量结果不同?
嘿,这个问题问得特别到位,刚好能帮你把Python参数传递和对象可变性这俩核心概念掰明白,咱们一步步拆解清楚。
先把两段代码和对应的输出列出来,方便对比:
第一段代码(自定义类实例)
class MyClass: def __init__(self, x): self.x = x def myfunct(arg): arg.x += 1 return arg a = MyClass(0) print(a.x) b = myfunct(a) print(a.x) print(b.x)
输出:
0 1 1
第二段代码(整数)
def myfunct(arg): arg += 1 return arg c = 0 print(c) d = myfunct(c) print(c) print(d)
输出:
0 0 1
核心原因:可变对象 vs 不可变对象
Python里的对象本质上分成两类,这是造成差异的关键:
- 可变对象:比如自定义类实例、列表、字典这类,它们的内部状态可以直接修改,不用重新生成一个新对象。
- 不可变对象:像整数、字符串、元组这种,它们的内部状态是固定的,任何看似“修改”的操作,其实都是生成了一个全新的对象。
结合按赋值传参机制分析
Python的参数传递是按赋值传参(passing by assignment),说白了就是:当你把变量传给函数时,其实是把变量指向的对象的引用,复制了一份给函数的形参。
第一段代码的运行逻辑:
a = MyClass(0):a指向一个MyClass的实例对象,这个对象的x属性是0。- 调用
myfunct(a):函数的形参arg拿到了和a一样的引用——也就是指向同一个实例对象。 arg.x += 1:这是在直接修改这个实例对象的内部属性,因为实例是可变对象,所以这个修改会直接作用在a指向的那个对象上。- 返回
arg:返回的还是同一个实例的引用,所以b和a指向的是同一个对象。
最后自然a.x和b.x都是1,原对象被实实在在修改了。
第二段代码的运行逻辑:
c = 0:c指向整数对象0,而整数是不可变对象。- 调用
myfunct(c):形参arg拿到了c指向的整数0的引用。 arg += 1:这可不是修改原有的0,而是生成了一个新的整数对象1,然后把arg的引用改成指向这个新对象——原来的0完全没动。- 返回
arg:返回的是新对象1的引用,所以d指向新对象,但c还是牢牢指着原来的0。
所以最后c还是0,d是1,原对象根本没被碰过。
一句话总结
当你在函数里操作参数时:
- 如果参数是可变对象,修改它的内部属性(比如
arg.x、arg.append())会直接影响原变量指向的对象; - 如果参数是不可变对象,任何“修改”操作都会生成新对象,对原变量指向的对象毫无影响。
内容的提问来源于stack exchange,提问作者gazoh
相关产品推荐
相关产品推荐

