python 物件/變數&賦值的幾點思考
python 物件/變數
物件
Every object has an identity, a type and a value.
- An object’s identity never changes once it has been created; you may think of it as the object’s address in memory. The ‘is’ operator compares the identity of two objects; the id() function returns an integer representing its identity (currently implemented as its address).
- An object’s type is also unchangeable. The type() function returns an object’s type (which is an object itself).
- The value of some objects can change. Objects whose value can change are said to be mutable; objects whose value is unchangeable once they are created are called immutable.
-
不可變(immutable)物件:
numbers, strings and tuples, etc.
可變物件的id 基本上可以理解為該物件記憶體地址,而python中名稱空間內的物件總是以標籤的方式來操作,例如a=3,它會在記憶體中尋找一個int型別的value為3的物件,如果有則將其記憶體地址作為a的id,假如沒有這樣的物件,則會先新建一個int型別的value為3的物件,再將其記憶體地址作為a的id。
class Obj(): def __init__(self,arg): self.x=arg if __name__ == '__main__': obj=Obj(1) print id(obj)#32754432 obj.x=2 print id(obj)#32754432 s="abc" print id(s)#140190448953184 s="bcd" print id(s)#32809848 x=1 print id(x)#15760488 x=2 print id(x)#15760464
-
可變(mutable)物件:
dictionaries and lists, etc.、
在python中不可變物件總是唯一的,即使兩個列表的大小,value對相同,但他們的id絕不可能相同,這是因為物件是可變的,假如id相同,則兩個變數將可以協同變化。
class Obj(): def __init__(self,arg): self.x=arg def __eq__(self,other): return self.x==other.x if __name__ == '__main__': obj1=Obj(1) obj2=Obj(1) print obj1 is obj2#False print obj1 == obj2#True lst1=[1] lst2=[1] print lst1 is lst2#False print lst1 == lst2#True s1='abc' s2='abc' print s1 is s2#True print s1 == s2#True a=2 b=1+1 print a is b#True a = 19998989890 b = 19998989889 +1 print a is b#False
物件賦值
在python中一切皆為物件,賦值操作即是改變名稱空間中的相應名字的指標,在相應的物件上即使反映為:從一個物件上撕下標籤,再將該標籤打到另外一個物件上。
對於可變物件來說,即為id地址的改變。
def fun(a): print "id(a):", id(a)# 56715624 a = 4 print "id(a):", id(a)# 56715600 print "a:", a b = 3 print "id(3):", id(3)# 56715624 fun(b) print "id(b):", id(b)# 56715624 print 'b:', b
首先建立了物件int 3,該物件即有了一個id,再將其賦值給b(屬於全域性名字空間),b的id與int 3的id相同,所以b指向了3.再進行函式操作fun(b)時,首先進行了a=b=3的操作,a與b與3的id相同,共同指向物件3,然後a又進行了賦值操作,因為物件是不可變的(type決定了),所以必須新建物件int 4,並將a指向4,所以a的id改變了,a的value也相應的改變了。但是b是屬於全域性名字空間的,b並沒有受到影響。
對於可變變數(列表)
def fun(a): print "id(a):", id(a)# 63265352a=b的操作,a、b的id相同 print a# [3, [2, 3]] print id(c)# 57698664指向全域性變數c a[0] = 1 print "id(a):", id(a)# 63265352修改了a的value,但是id並未改變 c = 3 b = [c, [2, 3]] print "id(c):", id(c)# 57698664 print "id(b):", id(b)# 63265352 fun(b) print "id(b):", id(b)# 63265352 print 'b:', b# [1, [2, 3]]b的id與a相同,a、b的value同時改變
在此處賦值時,先進行a=b的操作,a、b的id相同,所以在fun內改變了a[0],b也被改變了。
def fun(a): print "id(a):", id(a)# 54309000由於進行了copy操作,所以相當於傳遞了一個新的列表id給a,a的id與b則不相同了, a上的淺層(axis=0)修改對b不起作用,但深層次(axis>0)的修改依然有效嗎,這是因為此時a[1]與b[1]都指向同一個列表。 print a[0] is b[0]# False print a[1] is b[1]# True print a# [3, [2, 3]] a[0] = 1 a[1][0] = 0 print a# [1, [0, 3]] c = 3 b = [c, [2, 3]] print "id(c):", id(c)# 52455784 print "id(b):", id(b)# 54286920 fun(b[:])# 對b進行切片操作,即等於copy.copy(b) print "id(b):", id(b)# 54286920 print 'b:', b# [3, [0, 3]]
對列表的複製會產生一個新的列表,與新的列表id。
切片操作與淺層複製是相等的:a[:] 等價於 copy.copy[a]
深層複製可以迭代copy操作,使得列表中的列表也被複制,即完全產生一個新的value相同的列表,新列表與舊列表沒有任何聯絡,對列表中的列表的修改不會影響原列表。可以寫成copy.deepcopy(b)。
Reference
ofollow,noindex" target="_blank">Python中的id函式到底是什麼?
python基礎(5):深入理解 python 中的賦值、引用、拷貝、作用域