作为刚上完编译原理等专业课的小朋友,忍不住来看看函数参数传递过程中的内存情况,记录一下心路历程。
首先查资料,发现python不允许程序员选择采用传值还是传引用。
- 如果函数收到的是一个可变对象(比如字典或者列表)的引用,就能修改对象的原始值——相当于通过“传引用”来传递对象
- 如果函数收到的是一个不可变对象(比如数字、字符或者元组)的引用,就不能直接修改原始对象——相当于通过“传值’来传递对象。
我对于内存情况的预期是:
- 对于“传引用”的情况,形参和实参应该占用相同的内存区域
- 对于“传值”的情况,形参和实参应该占用不同的内存区域
测试一下,“传引用”符合预期:
def func(list1):
print(id(list1)) # 1460765511816
list1[0] = 666
list1 = [1,2,3]
print(id(list1)) # 1460765511816
func(list1)
print(list1) # [666,2,3]
“传值”比较有意思:
def func(x):
print(id(x)) # 1756475584,不符合预期
x = 2
print(id(x)) # 1756475616
x = 1
print(id(x)) # 1756475584
func(x)
可以看到,在对形参x进行“写”操作(x=2)之前,形参x和实参x地址相同,即并没有为形参x开辟新的内存空间,这不符合我之前的预期;“写”操作后,id(x)的结果就发生了变化,此时很明显这个x就不是之前的x了。猜测这应该是一种懒惰的做法,类似于“写时复制(copy-on-write)”。
的确,如果我们在函数内部只对x进行“读”操作,没必要产生一个新的局部变量,让栈无意义地增长消耗内存。