那些年在python中踩过的坑:调用方法时,对变量参数的修改问题

最近用python做题,因为对python的机制了解甚浅而踩了不少坑,关于方法中修改变量值的问题,吃亏很多次后终于懂了一丢丢,应该属于入门级的低端错误555555~仅记录一些自己不成熟的理解。

之前和同学开玩笑的时候说,python里面没有指针这个名词了,因为全都是指针。在调用方法的时候也要记得,传递的参数实际上是指向一个已经存在的对象,因此在子方法中操作变量时,也要根据它“指向的对象”来判断修改情况。

比如一个非常简单的例子:

def add(a):
    a += 1
    

a = 1

add(a)

a
Out[43]: 1

这个例子中的int值a可以换成字符串类型,会得到相同的结果,即无法在子方法外改变变量的值,要获取这个值我们就只能通过子方法的返回值,用一个变量来接住这个值(或者用全局变量)。为什么会这样呢,我们来看int型变量a在自增1之前的id变化:

a = 1

id(a)
Out[52]: 1690510000

a += 1 

id(a)
Out[54]: 1690510032

当a被自增时,它的id是变化的,也就是说,在子方法中我们实际上是用“a”这个名字覆盖了另一个值,这个值是原来a自增1的结果,但是子方法外的那个“a”,它的值变化了吗?并没有。有点类似于局部变量的意思。

字符串同理。

对于列表,它本身是可以进行原地修改的,我们就会看到:

def add(a):
    a[0] = 0
    

a = [1,2,3]

add(a)

a
Out[62]: [0, 2, 3]

显而易见地,我们有:

a = [1,2,3]

id(a)
Out[64]: 2435253695048

a[0] = 0

id(a)
Out[66]: 2435253695048

在子方法中,对列表进行任意形式切片操作或append、extend、insert,都是可以不借助返回值直接修改变量元素的,这其中的原因就是其“原地操作”的性质。而字符串是不可变数据类型,当我们写下a = "abc" a += "a" 这样的句子时,实际上是用一个新的地址覆盖了原来的。

对于列表,还有一个点,就是 += 这个操作。我们需要区别a = a + b 和 a += b。

a = a + b 式操作:

a = [1,2,3]

id(a)
Out[78]: 2435253692936

a = a + [0]

a
Out[80]: [1, 2, 3, 0]

id(a)
Out[81]: 2435252828808

a += b 式操作:

a = [1,2,3]

id(a)
Out[83]: 2435253690888

a += [0]

a
Out[85]: [1, 2, 3, 0]

id(a)
Out[86]: 2435253690888

容易看出,对于list(也许还有别的什么数据结构),+=是一个原地操作运算符,就是说在方法中可以通过+=修改列表元素。

最后皮一下:

def add(a):
    a = a + [0]
    a += [0]
    

a = [1,2,3]

add(a)

a
Out[90]: [1, 2, 3]

a的值是不变的,这一点虽然现在看起来显而易见,但是第一次我写出这种函数的时候真是百思不得其解,+=不是可以原地操作的吗?为什么我一直改不了数据?(ˉ▽ˉ;)...当时还调了大半天。

猜你喜欢

转载自blog.csdn.net/weixin_39655021/article/details/83657158