关于python的可变对象与不可变对象

  • 可变对象:该对象指向内存中的值可以发生改变。引用改变后,其所指内存上存的值也发生了改变。例如python中的数值类型(int、float)、字符串(str)、元祖(tuple)。
  • 不可变对象:该对象指向内存中的值不可以发生改变。引用改变后,指向一个新的内存块。例如python中的列表(list)、字典(dict)、集合(set)。


判断id是否相同使用 is,而判断值是否相同使用==

不可变对象:

  1. 数据类型:
a=10
b=a
c=10
print(id(a),id(b),id(c))
#1950969600 1950969600 1950969600

b=10+0
c=10+1
print(id(a),id(b),id(c))
#1950969600 1950969600 1950969632

print(id(11))
#1950969632

    再来看一下如果a、b、c都改变了原来的内存块是怎么处理的:

a=b=c=13
print(id(a),id(b),id(c))
#1950969696 1950969696 1950969696

print(id(10),id(11))
#1950969600 1950969632

可以发现10和11的内存块依旧存在,暂时不清楚python的垃圾回收机制,待后续继续研究。

2.字符串:

发现一个神奇的问题,先看下面三段代码:

astr="Helloworld"
bstr="Helloworld"
print(id(astr),id(bstr))
#2235114515248 2235114515248

bstr+=""
print(id(astr),id(bstr))
#2235114515248 2235114515248

########################################
astr="Helloworld!"
bstr="Helloworld!"
print(id(astr),id(bstr))
#2235114479664 2235114482032

bstr+=""
print(id(astr),id(bstr))
#2235114479664 2235114482032

astr==bstr
#True
#########################################
astr="Hello world"
bstr="Hello world"
print(id(astr),id(bstr))
#2235114497200 2235114545264

bstr+=""
print(id(astr),id(bstr))
#2235114497200 2235114545264

astr==bstr
#True

    可以看到字符串中如果只有字母,两个对象指向同一个地址,然而!!当字符串中出现了空格或者‘!’之类的符号时,两个对象虽然内容相同,但是指向的地址却不同了。这个原因有待考究。

3.元祖tuple

add = (1, 2, 3)
aee = (1, 2, 3)
print(id(add), id(aee), id((1, 2, 3)))  # id各不相同
#2235094251128 2235094238120 2235094250624

aee = (1, 2, 3)
print(id(aee)) #2235114527624
aee += () # 加空元组
print(id(aee))  # id变了!
#2235094251056

print(aee)  
#(1, 2, 3)

虽然看上去都是(1 ,2, 3)按理说应该和上面一致才对。难道这是可变对象?再看

add = (1, 2, 3)
aee = add 
print(id(aee), id(add)) # 这两个id一样

#2235094238048 2235094238048
aee += (4, 5, 6)
print(id(aee), id(add)) # aee的id变了,add的id没有变。
#2235114527624 2235094238048

print(add) # add还是(1, 2, 3)没有变
#(1, 2, 3)

又和数值类型于str类型一致了。如果是可变对象add = aee,它们指向同一地址(id相同)是肯定的。但不是同一对象的不同引用,因为如果是的话,aee的改变会引起add的改变,再tuple中并不是这样。所以tuple是不可变对象,但又和str和数值类型稍微有点区别。平常说的tuple不可变更多时候是指里面存放的值不能被改变(有些特殊情况,如tuple里面存放了list,可改变list里的元素。但实际上这个tuple并没有被改变)。



可变对象:

  1. list:
list1=[1,2,3]
list2=[1,2,3]
print(id(list1),id(list2),id([1,2,3]))
#2235114547208 2235114560648 2235114547016

    三个list指向不同的id,再看

alist = [1, 2, 3]
# alist实际上是对对象的引用,blist = alist即引用的传递,现在两个引用都指向了同一个对象(地址)
blist = alist
print(id(alist), id(blist))  # id一样
#2235114533832 2235114533832

# 所以其中一个变化,会影响到另外一个
blist.append(4)
print(alist)  # 改变blist, alist也变成了[1 ,2 ,3 4]
#[1 ,2 ,3 4]
print(id(alist), id(blist))  # id一样,和上面值没有改变时候的id也一样
#2235114533832 2235114533832

  但是如果是拷贝,就仅仅是将内容拷贝过去,传递的并是不引用。这在想使用列表的值又不想修改原列表的时候特别有用。

blist = alist[:]  # or alist.copy()
print(alist is blist)  # False
blist.append(4)
print(alist)  # 还是[1,2 ,3]没有变化
关于list的  +=   的问题:
a1 = [1, 2, 3]
a2 = a1
print(id(a1), id(a2))
a2 += [4]  # 相当于调用了a2.extend([4]),原地改变并没有新的对象产生
print(id(1), id(a2))  # 相等,a2的id没有变化
print(a1) 



  2.set

    
abb = {1, 2, 3}
acc = abb
print(id(abb), id(acc))
#2235113206504 2235113206504
acc.add(4)
print(abb)  
# {1, 2, 3, 4} 
print(id(abb), id(acc)) 
#2235113206504 2235113206504
可以看到和list是一样的。



你可能感兴趣的:(python)