day 06 列表去重, 資料型別的補充,編碼,深淺copy
因為重要,所以放前面
列表去重
l1 = [1, 2, 3, 4, 5] l2 = [3, 4, 5, 6, 7] set = list(set(l1 + l2)) # set自動去重,然後變成list型別 print(set) # [1, 2, 3, 4, 5, 6, 7]
1、 id is ==
== 是比較的兩邊的數值是否相等,而 is 是比較的兩邊的記憶體地址是否相等。 如果記憶體地址相等,那麼這兩邊其實是指向同一個記憶體地址。
l1 = [1, 2, 3] l2 = [1, 2, 3]print(l1, l2) print(id(l1), id(l2)) # 值相同,ID不同
l1 = [1, 2, 3] l2 = [1, 2, 3] print(l1 == l2) # True print(l1 is l2) # False
可以說如果記憶體地址相同,那麼值肯定相同,但是如果值相同,記憶體地址不一定相同。
程式碼塊: 瞭解
Python程式是由程式碼塊構造的。塊是一個python程式的文字,他是作為一個單元執行的。
程式碼塊:一個模組,一個函式,一個類,一個檔案等都是一個程式碼塊。
而作為互動方式輸入的每個命令都是一個程式碼塊。
對於一個檔案中的兩個函式,也分別是不同的程式碼塊
程式碼塊的快取機制 瞭解
程式碼塊的快取機制的適用範圍: int(float),str,bool
int(float):任何數字在同一程式碼塊下都會複用。
bool:True和False在字典中會以1,0方式存在,並且複用。
str:幾乎所有的字串都會符合快取機制
小資料池: 提升效率,節約記憶體
Python自動將-5~256的整數進行了快取,當你將這些整數賦值給變數時,並不會重新建立物件,而是使用已經建立好的快取物件。
python會將一定規則的字串在字串駐留池中,建立一份,當你將這些字串賦值給變數時,並不會重新建立物件, 而是使用在字串駐留池中建立好的物件。
其實,無論是快取還是字串駐留池,都是python做的一個優化,就是將~5-256的整數,和一定規則的字串,放在一個‘池’(容器,或者字典)中,無論程式中那些變數指向這些範圍內的整數或者字串,那麼他直接在這個‘池’中引用,言外之意,就是記憶體中之建立一個。
優點:能夠提高一些字串,整數處理人物在時間和空間上的效能;需要值相同的字串,整數的時候,直接從‘池’裡拿來用,避免頻繁的建立和銷燬,提升效率,節約記憶體。
總結:
如果在同一程式碼塊下,則採用同一程式碼塊下的換快取機制。
如果是不同程式碼塊,則採用小資料池的駐留機制
# pycharm 通過執行檔案的方式執行下列程式碼: 這是在同一個檔案下也就是同一程式碼塊下,採用同一程式碼塊下的快取機制。 i1 = 1000 i2 = 1000 print(i1 is i2) # 結果為True 因為程式碼塊下的快取機制適用於所有數字
通過互動方式中執行下面程式碼: # 這是不同程式碼塊下,則採用小資料池的駐留機制。 >>> i1 = 1000 >>> i2 = 1000 >>> print(i1 is i2) False # 不同程式碼塊下的小資料池駐留機制 數字的範圍只是-5~256.
# 雖然在同一個檔案中,但是函式本身就是程式碼塊,所以這是在兩個不同的程式碼塊下,不滿足小資料池(駐存機制),則指向兩個不同的地址。 def func(): i1 = 1000 print(id(i1)) # 2288555806672 def func2(): i1 = 1000 print(id(i1)) # 2288557317392 func() func2()
2、資料型別補充: int, str, bool,list,tuple,dict,set。
# 資料型別之間的轉換:
# str ---> list split
# list ---> str join
# bool :False 0 '' [] () {} set()
list <----> tuple
# list <---> tuple l1 = [1,2,3] tu1 = tuple(l1) l2 = list(tu1) print(tu1) print(l2)
list <------ dict
# list <---- dict dic1 = {'name': 'alex', 'age': 12} print(list(dic1))
list <------dict
# list <---- dict dic1 = {'name': 'alex', 'age': 12} print(list(dic1))
list <------> set
# list <---> set *** li = [1, 2, 3, 4, 5] set = set(li) print(set, type(set)) set = {1, 2, 3, 4, 5} list = list(set) print(list)
元組補充:
元組中只有一個元素並且沒有逗號,則他不是元組,與元素資料型別相同。
tu1 = (1) tu2 = (1) print(tu1, id(tu1), type(tu1)) # 1 1558496944 <class 'int'> print(tu2, id(tu2), type(tu2)) # 1 1558496944 <class 'int'> tu1 = (1,) tu2 = (1,) print(tu1, id(tu1), type(tu1)) # (1,) 2880293370120 <class 'tuple'> print(tu2, id(tu2), type(tu2)) # (1,) 2880294252048 <class 'tuple'>
踩坑題
坑1:li = [11, 22, 33, 'alex', 55] 將列表中索引為奇數位的元素刪除
錯誤事例:
li = [11, 22, 33, 'alex', 55] for index in range(len(li)): if index % 2 == 1: li.pop(index) print(li) # [11, 33, 'alex'] 刪除的是索引為1,4 的元素 # 原因:pop在刪除索引1後,會將後面元素,全部向前提一位 (補空) # 解決方法: 迴圈從後面開始
解決方法:
一,從後面開始迴圈
li = [11, 22, 33, 'alex', 55] for index in range(len(li)-1, -1, -1): if index % 2 == 1: li.pop(index) print(li)
二,建立新列表,將偶數選出,然後覆蓋 li 列表
li = [11, 22, 33, 'alex', 55] l1 = [] for index in range(len(li)): if index % 2 == 0: l1.append(li[index]) li = l1 print(li)
總結:在迴圈一個列表時,最好不要改變列表的大小,這樣會影響你的最終結果
坑二:
dic = {'k1':1,'k2':2, 'k3': 3, 'name': '太白'}
將字典中鍵含有k元素的鍵值對刪除
錯誤示例:
dic = {'k1':1,'k2':2, 'k3': 3, 'name': '太白'} for key in dic: if 'k' in key: dic.pop(key) l1 = []
# 結果報錯 dictionary changed size during iteration
解決方法:
dic = {'k1': 1, 'k2': 2, 'k3': 3, 'name': '太白'} l1 = [] for key in dic: if 'k' in key: l1.append(key) for k1 in l1: dic.pop(k1) print(dic)
總結:dict 在迴圈一個字典時,不能改變字典的大小,會報錯
編碼的進階:
ascii,unico,utp-8,gbk四個編碼本:
1,不同的編碼之間能否互相識別(報錯或者出現亂碼)。 不能!!
2, 規定:文字通過網路傳輸,或者硬碟儲存不能使用Unicode編碼方式。 耗記憶體
大前提:
python3x環境:
唯獨str型別:他在內部編碼方式是unicode
所以 python3x中的字串不能用於直接的網路傳輸 檔案的儲存 '中午請我去吃飯'
補充一個數據型別:bytes型別 與str型別是海爾兄弟。
為啥要有bytes:
bytes內部編碼方式非unicode
為啥還要有str? bytes直接就解決了所有問題呀?
bytes 中文是16進製表示,看不懂。
英文:
str:
表現形式:'alex'
內部編碼:unicode
bytes:
表現形式:b'alex'
內部編碼:非unicode
中文:
str:
表現形式:'屌絲'
內部編碼:unicode
bytes:
表現形式:b'\xe5\xb1\x8c\xe4\xb8\x9d''
內部編碼:非unicode
bytes:當你需要網路傳輸資料,檔案儲存資料時要考慮到bytes。
str ---> bytes(gbk utf-8)
unicode ---> gbk utf-8
bype 用法:
s1 = 'alex' b1 = b'alex' print(b1,type(b1)) # b'alex' <class 'bytes'> print(b1.upper()) # b'ALEX'
編碼之間的轉換
# unicode ---> gbk 字串 ---> gbk編碼方式的bytes s1 = '太白' b1 = s1.encode('gbk') # 編碼 s2 = b1.decode('gbk') # 解碼 print(s2)
# unicode ---> utf-8 字串 ---> utf-8 編碼方式的bytes s2 = '太白' b2 = s2.encode('utf-8') s3 = b2.decode('utf-8') print(s3)
# gbk ---> utf-8 # b1 = b'\xcc\xab\xb0\xd7' # gbk編碼的bytes型別 s = b1.decode('gbk') b2 = s.encode('utf-8') # utf-8編碼的bytes型別 print(b2)
深淺copy
淺copy,在記憶體中建立一個新的list(dict),但是新的列表裡面的元素還是與原列表共用一個
# 淺copy # 在記憶體中建立一個新的list(dict),但是新的列表裡面的元素還是與原列表共用一個。 l1 = [1, 'alex', [11, 22]] l2 = l1.copy() print(id(l1), id(l2)) # 1893402849992 1893402850760 l1.append(33) print(l1, l2) # [1, 'alex', [11, 22], 33] [1, 'alex', [11, 22]] print(id(l1[0])) # 1558496944 print(id(l2[0])) # 1558496944 print(id(l1[-1])) # 1558497968 print(id(l2[-1])) # 1893402827784 print(l1 is l2) # print(l1 is l2)
深COPY
深copy會在記憶體中對原列表(dict)以及列表裡面的可變的資料型別重新建立一份,而列表中不可變的資料型別還是沿用原來的
import copy l1 = [1, 'alex', [11,22]] l2 = copy.deepcopy(l1) # l1[0] = 1000 print(l1) print(l2) # print(id(l1)) print(id(l2)) print(id(l1[-1])) # 2190627337480 print(id(l2[-1])) # 2190627338888 print(id(l1[0])) print(id(l2[0])) l1[-1].append(666) print(l1) print(l2)