本来正在写递归,但是又一次遇到了关于python 的小问题,先记录下来,以备不时之需(话说这已经是我写的第二篇传参问题了啊喂,,,)。

附上之前遇到的问题:

下面我们分三种情况来讨论:

case1,参数为不可变对象(数值类型(int和float)、字符串str、元组tuple都是不可变类型),python 通过值传递:

def change(val):
print('val ',id(val))
val += 10
print('val ',id(val))
nums = 20
print(nums)
print('nums',id(nums))
change(nums)
print('nums',id(nums))
print(nums)

运行结果如下:

20

nums 2016306105392

val 2016306105392

val 2016306105584

nums 2016306105392

20

这个应该很好理解,我仿佛已经听到了大家在说 “naive” 的声音。

case2,参数为可变对象(列表list、字典dict、集合set是可变类型),python 通过引用传递:

def change(val):
print('val ',id(val))
val.append(10) #大家可以留意一下这句话
print('val ',id(val))
nums = [0, 1]
print(nums)
print('nums',id(nums))
change(nums)
print('nums',id(nums))
print(nums)

运行结果如下:

[0, 1]

nums 2802784706440

val 2802784706440

val 2802784706440

nums 2802784706440

[0, 1, 10]

可以非常清楚的看到,nums的值发生了改变,而函数当中的val,其实就是nums。

case3,参数为可变对象,但传递过去的参数又指向了其他对象:

def change(val):
print('val ',id(val))
val = val + [10] #这句是关键,经过该赋值语句,此 val 已非彼 val
print('val ',id(val))
nums = [0, 1]
print(nums)
print('nums',id(nums))
change(nums)
print('nums',id(nums))
print(nums)

运行结果如下:

[0, 1]

nums 2248343854984

val 2248343854984

val 2248343905672

nums 2248343854984

[0, 1]

我们可以看出,若传递过去的参数指向了其他对象,则对该对象的操作并不影响原变量的对象值。也就是说,刚传进函数时,val 和 nums 是一样的,但是经过了赋值之后,val发生了改变,此时 val 指向了与 nums 不同的内存变量,所以最终 nums 还是我们熟悉的那个 nums,但val 已经不是我们认识的 val 了~

其实道理也极其简单,第三种情况就是第二种情况的特殊例子,如果不好理解的话,我可以把代码换成如下形式:

def change(val):
print('val ',id(val))
new_val = val + [10] #其他的不用看了,变的还是这一行代码
print('new_val ',id(val))
nums = [0, 1]
print(nums)
print('nums',id(nums))
change(nums)
print('nums',id(nums))
print(nums)

这下是不是清晰了一些呢?我虽然把 nums 传递过去了,但是我并没有改变它的值,我只是用它做了一些计算而已,那么 val 在函数当中都没有发生变化,又怎么会影响到 nums 呢?