我的python版本:3.8.6
不可变对象immutable:对象内容不可原地改变
不可变的对象有:int、字符串(string)、float、元组(tuple)
a=10
b=a
print(id(a))
print(id(b))
print()
b=11
print(id(a))
print(id(b))
#输出:
#140736928221120
#140736928221120
#
#140736928221120
#140736928221152
可以看到,b=10时它的地址是与a一样的,在b=11后它的地址就变了。python变量都是指针,不可变对象的指针并不是固定地指向一个地址,而是“我的值是10,那我就指向存放10的那个地址,我的值改成11了,那我就指向存放11的那个地址”,原来放10的那个地址依然是10,所以准确地说,变量改变的是指针指向。
值得一说的是,python中有一个小整数的概念,指的是[-5,256]这个区间的整数,它们放在一个small_int的数组里,用户使用这个区间的int的时候系统就会直接从这个数组里引用,所以前后两次执行两次的id()是一样的,而不在这个区间的int(大整数)以及其它不可变对象在程序每次程序执行时都会新分配一个地址,每次执行的id都是随机的。
print(id(257))
#第一次执行:1675989624976
#第二次执行:1865732470928
#第三次执行:1928663681168
至于string对象,python有个intern机制(字符串驻留),它就是一个字典,以字符串为key,以地址为value,每个字符串及其被分配的地址都会放在这个字典里,每次定义字符串对象的时候都会和这个字典比较,有了就直接引用,省点空间,没有就创建。
a='abc'
b='abc'
print(id(a)==id(b))#True
字符串是不可变对象,我们用replace()函数把a的对象’abc’改成’def’,字符串使用replace需要重新赋值,生成一个新的对象,变量a指向这个新对象,而不是原来的’abc’上面做更改。现在知道什么叫‘不可变’了吧。
a='abc'
print(id(a))#2352432259120
a=a.replace('abc','z')
print(id(a))#2352452781232
#两次id不同了,a指向了新的对象
可变对象:对象内容可以原地改变
解释器为每个对象维护不同内存区域,每个可变对象都由解释器重新创建内存空间,并不复用。
可变对象有:字典(dict)、列表(list)、集合(set)
lt1=[1,2,3,4]
lt2=lt1
lt3=[1,2,3,4]
print(id(lt1))#2567070829824
print(id(lt2))#2567070829824
print(id(lt3))#2567070868928
#lt1:新建对象;lt2:引用对象;lt3:新建对象。
lt1.append(100)
print(lt1)#[1, 2, 3, 4, 100]
print(lt2)#[1, 2, 3, 4, 100]
print(lt3)#[1, 2, 3, 4]
print(id(lt1))#2567070829824
lt2只是引用lt1的对象,两者指向同一地址,多个引用,并不是多个对象,其中一个的变化会影响的另外一个。而lt3是一个新对象,尽管它也是[1,2,3,4],但并不因为对象的值相等就指向同一对象,lt1和lt2的变化与lt3无关。
lt1的对象虽然变化了,但变化前后的id并不改变,还是那个地址,这就是‘可变的’对象。
可变对象/不可变对象作为函数参数
可变对象函数参数时,函数内对参数的对象的改变会影响到原始对象;
不可变对象作为参数时,函数内对参数的改变不会影响到原始参数,改变的是函数内变量的指向对象。