天天看点

可变类型和不可变类型及函数传参

a = 100
b = a
print('a:%d'%id(a))
print('b:%d'%id(b))
a = 200
print('a:%d'%id(a))
print(b, "b:%d"%id(b))
           
# 运行结果
a:1965193792
b:1965193792
a:1965196992
100 b:1965193792
           

以上内容分为四部分理解:

  • a定义为整数类型变量,不可变.
  • b指向了a变量的地址
  • 当对a重新赋值的时候,a的地址也发生了改变.因为a为不可变类型,所以当a的值进行修改时,其实是又开辟了新的空间,然后a指向了新的地址,这就是不可变类型的具体表现,就是我定义变量的时候,如a=100,这个时候,内存会存放100这个数值,所以开辟了空间,但是这个空间存放的值必须是100,当对值进行改变是,之前的这片空间就不可以用了, 只能继续开辟新的空间
  • 为什么当a改变的时候,b却没有改变呢,赋值相当于是简单地拷贝对象的引用,两个对象的id相同,所以其实b指向的是a所指向的地址,因为b所指的地址的值并没有发生改变,所以b的值也不会发上改变
上面的懂了之后,来看下面的
a = [1]
b = a
print(id(a),id(b))
a = [1,2]
print(id(a),id(b))
           
  • 我们现在定义的是一个可变类型,按正常来讲当a的值改变的时候,但是a所指的地址不会变,然后此时b又指向了a的地址,所以b的值应该会和a一起变
# 运行结果
2187008223624 2187008223624
2187007395912 2187008223624
           
  • 看第二行第一个a的地址发生了改变,和我们想的不一样
# 试着来输出一下b
[1]
           
  • 这一点也和我们想的不一样,为什么呢?

    首先:a是可变类型的变量确实没有错,然后b指向a的地址也没有错.但是我们在定义下面那个a的时候,注意:a=[1,2],我们是相当于重新定义了一个列表,并不是之前的列表了,也就是此a非彼a.那怎么才能和我们之前所想的一致呢?

a = [1]
b = a
a.append(2)
print(a,id(a))
print(b,id(b))

# 运行结果
[1, 2] 1890279631240
[1, 2] 1890279631240
           
  • 看上面的是不是就和我们之前所想的贴切了.一定要分清出我们到底是重新定义了变量,还是在之前的变量上进行了改变.
函数中参数传递的都是引用:
def f(a):
    print(id(a))
    a = 10
    print(id(a))
a = 5
f(a)
print(id(a))
print(a)

# 运行结果
1961848416
1961848576
1961848416
5
           
  • 函数参数传递的是一个引用,所以a一开始所指向的地址是a定义时候的地址,但是当在函数内对a进行了重新定义,所以a函数内a的地址就发生了改变
这时候,我们可以看下全局变量的作用
def f():
    global a
    a = 10
    print(id(a))
a = 5
print(id(a))
f()
print(id(a))

# 运行结果
1965190752
1965190912
1965190912
           
  • 也就是说global对于全局变量进行了赋值,同时他指向的地址也发生了改变
--------------------------------------------------------------------
def f(list1):
    list1 = [1,2]
list1 = [1]
f(list1)
print(list1)
           
  • 这里的问题之前也说明过,虽然list1是个可变类型,但是我们在函数中的修改相当于是对变量的重新赋值.也就是重新开辟了一快空间,并不是对之前的list1进行修改
def f(list1):
    list1 += [3]
list1 = [1]
f(list1)
print(list1)

# 运行结果
[1, 3]