數據的在內存中的地址就是數據的引用。
如果兩個變量為同一個引用,那么這兩個變量對應的數據一定相同;
如果兩個變量對應的數據相同,引用不一定相同。
通過id(數據)可以查看數據對應的地址,修改變量的值,其實是在修改變量的引用。
數據可以分為:可變類型與不變類型
可變類型:
如果修改了數據的內容,數據的地址沒有發生改變.
有列表,字典,set集合
不可變類型:
如果修改了數據的內容,數據的地址發生改變.
有字符串,元組,數字
當python解釋器首次啟動時,會把小數字(-5~256)和短字符串(長度小於21)緩存到緩沖區中,當在程序中使用這些數字和字符串時,就直接從緩存區中取。
m = 300
n = 300
print(id(m)) # 1811121856
print(id(n))
不在小數字或者小字符串范圍內的數據,會在第一次使用時緩存起來
m = 300
n = 300
print(id(m)) # 2345027009360
print(id(n)) # 2345027009360
演示:
1.
變量a實際存儲的是1的引用(地址)(在程序執行過程中a被編譯為一條指令)
a = 1
b = a
print(id(a)) # 1820749280
print(id(b)) # 1820749280
a =2 # 修改不可變類型(的引用)
print(id(a)) # 1820749312 a的id已經改變
print(id(b)) # 1820749280
print(a,b)
a = [1, 2,[3,5]]
b = a
print(id(a)) # 1758314288776
print(id(b)) # 1758314288776
# a.append(3)
a[0] = 6
a[2][0] = 1
b[2][1] = 6
print(id(a)) # 1758314288776 注意a與b始終指向同一個地址
print(id(b)) # 1758314288776
print(a) # [6, 2, [1, 6]]
print(b) # [6, 2, [1, 6]]
2.
list = []
dict = {"name":"wangjie","age":23}
print(id(dict))
a = 10
list.append(dict) # 把dict的引用加入到list中 0x111 的內容是(指向){"name":"wangjie","age":23}
list.append(a) # 把a的引用加入到list中 0x222 的內容是(指向)10
print(list) # list[0] 為0x111 ,內容是(指向)數據{"name":"wangjie","age":23},list[1]的內容0x222,內容是(指向)數據10
a = 20 # 修改了a的值 a的引用發生的變化 0x333
# 但不影響list中的引用指向的值 還是指向0x111 指向{"name":"wangjie","age":23}
# 和0x222 指向 10
print(list)
dict["name"] = "lili" #修改了dict的值 dict為可變數據類型,dict的引用不變,但0x111的內容已經變為{'name': 'lili', 'age': 23}
print(list) # list[0]的內容是 0x111 , 指向數據{'name': 'lili', 'age': 23},list[1]的內容為0x222指向數據 10
3.
list = []
list2 = []
m = 10
def func():
global m
m =20
list2 = [1,2] # 不屬於修改,修改需要通過方法,這種是覆蓋全局變量list2
list.append(1) # 通過append 方法修改,list的引用不變
print(list2) # [1, 2]
print(list) # []
print(m) # 10
print(id(m)) # 1811115776
func() # [1, 2]
print(list) # [1]
print(list2) # []
print(m) # 20
print(id(m)) # 1811116096
4.
def log2():
#info_dict = {} # 存儲學生信息的字典若放在for循環外,則舊數據會被新數據覆蓋
info_list = []
num = input("請輸入要錄入信息的數量")
num = int(num)
for i in range(num):
info_dict = {} # 重新直接對info_dict 賦值,info_dict的引用發生改變 存儲學生信息的字典要放在for循環# 內
print("錄入第%s 位信息" % (i + 1))
name = input("輸入姓名:")
id = input("輸入學號")
info_dict["姓名"] = name
info_dict["學號"] = id
info_list.append(info_dict)
print(info_list)
for info in info_list:
for k ,v in info.items():
print('%s = %s' % (k,v))
log2()
5.
a = [1, 2]
b = [3, 4]
a.append(b) # [1,2,[3,4]]
b.append(a)
print(a) # [1, 2, [3, 4, [...]]]
print(b) # [3, 4, [1, 2, [...]]]
6.傳遞數據,傳遞的是數據對應的地址.
a = [[]] * 5
print(a) [[],[],[],[],[]]
print(id(a)) # 2132205131400
print(id(a[0])) # 2132205131592
print(id(a[1])) # 2132205131592
a.append(1)
print(id(a)) # 2132205131400
print(a) # [[],[],[],[],[],1]
a[0].append(2)
print(id(a[0])) # 2132205131592
print(a) # [[2],[2],[2],[2],[2],1]
a[1].append(3)
print(id(a[1])) # 2132205131592
print(a) # [[2,3],[2,3],[2,3],[2,3],[2,3],1]
7.
>>> def selfAdd(a):
"""自增"""
a += a
>>> a_int = 1
>>> selfAdd(a_int)
>>> a_int
1
>>> a_list = [1,2]
>>> selfAdd(a_list)
>>> a_list
[1, 2, 1, 2]
總結:python中函數參數是引用傳遞(注意不是值傳遞)。對於不可變類型,因變量的值不能修改,所以運算不會影響到變量自身;而對於可變類型來說,函數體中的運算有可能
會更改傳入參數的值
8.
+= 和append()方法等對數據引用的修改一樣
9.
a = [1,2]
b = a * 2
print(b) # [1,2,1,2]
print(id(b)) # 2745079031688
b[0] = 55
print(b) # [55,2,1,2]
print(id(b)) # 2745079031688
print(a) # [1,2]
修改了b[0] ,則b[0] 的引用發生改變,但b的引用沒發生變化
9.
第一種情況:
def func(x,l = []):
for i in range(x):
l.append(i+1)
print(l)
func(3) # [1,2,3]
func(2) # [1,2,3,1,2]
第二種情況:
def func(x,l = []):
for i in range(x):
l.append(i+1)
print(l)
list = [1,2]
func(3,list) # [1,2,1,2,3]
func(2) # [1,2]
函數有默認參數,定義時即為默認參數分配地址了,也只分配這一個地址,所以第一種情況,用的全是l這個列表;第二種調用func(3,list),將list變為了[1,2,1,2,3],然后調用func(2),l又指向了原先的已經定義好的空列表,所以結果為[1,2]。
