萬惡之源 - Python基礎數據類型三
字典
字典的簡單介紹
字典(dict)是python中唯?的?個映射類型.他是以{ }括起來的鍵值對組成.
在dict中key是 唯?的.在保存的時候, 根據key來計算出?個內存地址. 然後將key-value保存在這個地址中.
這種算法被稱為hash算法, 所以, 切記, 在dict中存儲的key-value中的key必須是可hash的, 如果你搞不懂什麽是可哈希, 暫時可以這樣記,
可以改變的都是不可哈希的, 那麽可哈希就意味著不可變. 這個是為了能準確的計算內存地址?規定的.
已知的可哈希(不可變)的數據類型: int, str, tuple, bool 不可哈希(可變)的數據類型: list, dict, set
語法:{‘key1‘:1,‘key2‘:2}
註意: key必須是不可變(可哈希)的. value沒有要求.可以保存任意類型的數據
# 合法 dic = {123: 456, True: 999, "id": 1, "name": ‘sylar‘, "age": 18, "stu": [‘帥 哥‘, ‘美?‘], (1, 2, 3): ‘麻花藤‘} print(dic[123]) print(dic[True]) print(dic[‘id‘]) print(dic[‘stu‘]) print(dic[(1, 2, 3)]) # 不合法 # dic = {[1, 2, 3]: ‘周傑倫‘} # list是可變的. 不能作為key # dic = {{1: 2}: "哈哈哈"} # dict是可變的. 不能作為key dic = {{1, 2, 3}: ‘呵呵呵‘} # set是可變的, 不能作為key
註意:dict保存的數據不是按照我們添加進去的順序保存的. 是按照hash表的順序保存的. ?hash表 不是連續的. 所以不能進?切片?作. 它只能通過key來獲取dict中的數據
字典操作:
增
dic = {} dic[‘name‘] = ‘汪峰‘ dic[‘age‘] = 18 print(dic) 結果: {‘name‘: ‘汪峰‘, ‘age‘: 18} # 如果dict中沒有出現這個key,就會將key-value組合添加到這個字典中 # 如果dict中沒有出現過這個key-value. 可以通過setdefault設置默認值 s1 = dic.setdefault(‘王菲‘) print(s1) print(dic) 結果: None # 返回的是添加進去的值 {‘王菲‘: None} # 我們使用setdefault這個方法 裏邊放的這個內容是我們字典的健,這樣我們添加出來的結果 就是值是一個None dic.setdefault(‘王菲‘,歌手) # 這樣就是不會進行添加操作了,因為王菲在dic這個字典中存在 # 總結: 當setdefault中第一個參數存在這個字典中就就不進行添加操作,否則就添加 dic1 = {} s2 = dic1.setdefault(‘王菲‘,‘歌手‘) print(s2) print(dic1) 結果: 歌手 {‘王菲‘: ‘歌手‘}
刪
dic = {‘劍聖‘:‘易‘,‘哈啥給‘:‘劍豪‘,‘大寶劍‘:‘蓋倫‘} s = dic.pop(‘哈啥給‘) # pop刪除有返回值,返回的是被刪的值 print(s) print(dic) # 打印刪除後的字典 dic.popitem() # 隨機刪除 python3.6是刪除最後一個 print(dic) dic.clear() # 清空
改
dic = {‘劍聖‘:‘易‘,‘哈啥給‘:‘劍豪‘,‘大寶劍‘:‘蓋倫‘} dic[‘哈啥給‘] = ‘劍姬‘ # 當哈啥給是字典中的健這樣寫就是修改對應的值,如果不存在就是添加 print(dic) dic.update({‘key‘:‘v‘,‘哈啥給‘:‘劍姬‘}) # 當update中的字典裏沒有dic中鍵值對就添加到dic字典中,如果有就修改裏邊的對應的值 print(dic)
查
dic = {‘劍聖‘:‘易‘,‘哈啥給‘:‘劍豪‘,‘大寶劍‘:‘蓋倫‘} s = dic[‘大寶劍‘] #通過健來查看,如果這個健不在這個字典中.就會報錯 print(s) s1 = dic.get(‘劍聖‘) #通過健來查看,如果這個健不在這個字典中.就會返回None print(s1) s2 = dic.get(‘劍姬‘,‘沒有還查你是不是傻‘) # 我們可以在get查找的時候自己定義返回的結果 print(s2)
練習
dic = {‘k1‘: "v1", "k2": "v2", "k3": [11,22,33]} 請在字典中添加一個鍵值對,"k4": "v4",輸出添加後的字典 請在修改字典中 "k1" 對應的值為 "alex",輸出修改後的字典 請在k3對應的值中追加一個元素 44,輸出修改後的字典 請在k3對應的值的第 1 個位置插入個元素 18,輸出修改後的字典
其他操作
key_list = dic.keys() print(key_list) 結果: dict_keys([‘劍聖‘, ‘哈啥給‘, ‘大寶劍‘]) # 一個高仿列表,存放的都是字典中的key value_list = dic.values() print(value_list) 結果: dict_values([‘易‘, ‘劍豪‘, ‘蓋倫‘]) #一個高仿列表,存放都是字典中的value key_value_list = dic.items() print(key_value_list) 結果: dict_items([(‘劍聖‘, ‘易‘), (‘哈啥給‘, ‘劍豪‘), (‘大寶劍‘, ‘蓋倫‘)]) # 一個高仿列表,存放是多個元祖,元祖中第一個是字典中的鍵,第二個是字典中的值
練習
循環打印字典的值
循環打印字典的鍵
循環打印元祖形式的鍵值對
dic = {‘劍聖‘:‘易‘,‘哈啥給‘:‘劍豪‘,‘大寶劍‘:‘蓋倫‘} for i in dic: print(i) 結果: 易 劍豪 蓋倫 for i in dic.keys(): print(i) 結果: 易 劍豪 蓋倫循環打印字典中的鍵
dic = {‘劍聖‘:‘易‘,‘哈啥給‘:‘劍豪‘,‘大寶劍‘:‘蓋倫‘} for i in dic: print(dic[i]) 結果: 易 劍豪 蓋倫 for i in dic.values(): print(i) 結果: 易 劍豪 蓋倫循環打印字典中的值
dic = {‘劍聖‘:‘易‘,‘哈啥給‘:‘劍豪‘,‘大寶劍‘:‘蓋倫‘} for i in dic.items(): print(i) 結果: (‘劍聖‘, ‘易‘) (‘哈啥給‘, ‘劍豪‘) (‘大寶劍‘, ‘蓋倫‘)循環打印元祖形式的鍵值對
解構
a,b = 1,2 print(a,b) 結果: 1 2 a,b = (‘你好‘,‘世界‘) print(a,b) 結果: 你好 世界 a,b = [‘你好‘,‘大飛哥‘] print(a,b) 結果: 你好 世界 a,b = {‘汪峰‘:‘北京北京‘,‘王菲‘:‘天後‘} print(a,b) 結果: 汪峰 王菲
循環字典獲取鍵和值
for k,v in dic.items(): print(‘這是鍵‘,k) print(‘這是值‘,v) 結果: 這是鍵 劍聖 這是值 易 這是鍵 哈啥給 這是值 劍豪 這是鍵 大寶劍 這是值 蓋倫
字典的嵌套
dic = { ‘name‘:‘汪峰‘, ‘age‘:48, ‘wife‘:[{‘name‘:‘國際章‘,‘age‘:38}], ‘children‘:[‘第一個熊孩子‘,‘第二個熊孩子‘] }
獲取汪峰的妻子名字
d1 = dic[‘wife‘][0][‘name‘] print(d1)
獲取汪峰的孩子們
d2 = dic[‘children‘] print(d2)
獲取汪峰的第一個孩子
d3 = dic[‘children‘][0] print(d3)
練習
dic1 = { ‘name‘:[‘alex‘,2,3,5], ‘job‘:‘teacher‘, ‘oldboy‘:{‘alex‘:[‘python1‘,‘python2‘,100]} } 1,將name對應的列表追加?個元素’wusir’。 2,將name對應的列表中的alex?字??寫。 3,oldboy對應的字典加?個鍵值對’?男孩’,’linux’。 4,將oldboy對應的字典中的alex對應的列表中的python2刪除
小數據池
接下來我們學習下小數據池,在學小數據池之前我們來看下代碼塊
根據提示我們從官方文檔找到了這樣的說法: A Python program is constructed from code blocks. A block is a piece of Python program text that is executed as a unit. The following are blocks: a module, a function body, and a class definition. Each command typed interactively is a block. A script file (a file given as standard input to the interpreter or specified as a command line argument to the interpreter) is a code block. A script command (a command specified on the interpreter command line with the ‘-c‘ option) is a code block. The string argument passed to the built-in functions eval() and exec() is a code block. A code block is executed in an execution frame. A frame contains some administrative information (used for debugging) and determines where and how execution continues after the code block’s execution has completed.
上面的主要意思是:
Python程序是由代碼塊構造的。塊是一個python程序的文本,他是作為一個單元執行的。
代碼塊:一個模塊,一個函數,一個類,一個文件等都是一個代碼塊。
而作為交互方式輸入的每個命令都是一個代碼塊。
什麽叫交互方式?就是咱們在cmd中進入Python解釋器裏面,每一行代碼都是一個代碼塊,例如:
而對於一個文件中的兩個函數,也分別是兩個不同的代碼塊:
OK,那麽現在我們了解了代碼塊,我們就來看看小數據池和代碼塊有啥關系,
id is ==
在Python中,id是什麽?id是內存地址,比如你利用id()內置函數去查詢一個數據的內存地址:
name = ‘meet‘ s_id = id(name) # 通過內置方法獲取name變量對應的值在內存中的編號 print(s_id) # 2055782908568 這就是name在內存中的編號
那麽 is 是什麽? == 又是什麽?
== 是比較的兩邊的數值是否相等,而 is 是比較的兩邊的內存地址是否相等。 如果內存地址相等,那麽這兩邊其實是指向同一個內存地址。
可以說如果內存地址相同,那麽值肯定相同,但是如果值相同,內存地址不一定相同,如圖:
這就很神奇了,剛剛還不是一個內存地址呢,現在怎麽又是一個內存地址了,其中神奇之處就是我們的小數據池
小數據池,也稱為小整數緩存機制,或者稱為駐留機制等等. 那麽到底什麽是小數據池?他有什麽作用呢?
註意:小數據池,只針對,整數,字符串,bool值
官方對於整數,字符串的小數據池是這麽說的:
對於整數,Python官方文檔中這麽說: The current implementation keeps an array of integer objects for all integers between -5 and 256, when you create an int in that range you actually just get back a reference to the existing object. So it should be possible to change the value of 1. I suspect the behaviour of Python in this case is undefined. 對於字符串: Incomputer science, string interning is a method of storing only onecopy of each distinct string value, which must be immutable. Interning strings makes some stringprocessing tasks more time- or space-efficient at the cost of requiring moretime when the string is created or interned. The distinct values are stored ina string intern pool. –引自維基百科
在python中對-5到256之間的整數會被駐留在內存中. 將?定規則的字符串緩存. 在使? 的時候, 內存中只會創建?個該數據的對象. 保存在?數據池中. 當使?的時候直接從?數據 池中獲取對象的內存引?. ?不需要創建?個新的數據. 這樣會節省更多的內存區域.
優點:
能夠提??些字符串, 整數的處理速度. 省略的創建對象的過程.
缺點:
在‘池‘中創建或者插入新的內容會花費更多的時間.
對於數字:
-5~256是會被加到?數據池中的. 每次使?都是同?個對象.
對於字符串:
1. 如果字符串的?度是0或者1, 都會默認進?緩存
2. 字符串?度?於1, 但是字符串中只包含字?, 數字, 下劃線時才會緩存
3. ?乘法的到的字符串.
①. 乘數為1, 僅包含數字, 字?, 下劃線時會被緩存. 如果 包含其他字符, ??度<=1 也會被駐存
②. 乘數?於1 . 僅包含數字, 字?, 下劃 線這個時候會被緩存. 但字符串?度不能?於20 4. 指定駐留. 我們可以通過sys模塊中的intern()函數來指定要駐留的內容.
OK. 到?前為?. 我們已經了解了python的?數據池的?些基本情況了. 但是!!!!
還有最後? 個問題. ?數據池和最開始的代碼塊有什麽關系呢?
同樣的?段代碼在命令?窗?和在py?件中. 出現的效果是完全不?樣的.
註意. 在py?件中.得到的結果是True, 但是在cmd中就不是了.
在代碼塊內的緩存機制是不?樣的. 在執?同?個代碼塊的初始化對象的命令時, 會檢 查是否其值是否已經存在, 如果存在, 會將其重?.
換句話說: 執?同?個代碼塊時, 遇到初始 化對象的命令時,他會將初始化的這個變量與值存儲在?個字典中, 在遇到新的變量時, 會先 在字典中查詢記錄,
如果有同樣的記錄那麽它會重復使?這個字典中的之前的這個值. 所以在 你給出的例?中, ?件執?時(同?個代碼塊) 會把a, b兩個變量指向同?個對象.
如果是不同的代碼塊, 他就會看這個兩個變量是否是滿??數據池的數據, 如果是滿? ?數據池的數據則會指向同?個地址.
所以: a, b的賦值語句分別被當作兩個代碼塊執?, 但是他們不滿??數據池的數據所以會得到兩個不同的對象, 因?is判斷返回False
集合(set)
set集合是python的?個基本數據類型. ?般不是很常?. set中的元素是不重復的.?序的.? ?的元素必須是可hash的(int, str, tuple,bool), 我們可以這樣來記. set就是dict類型的數據但 是不保存value, 只保存key. set也?{}表?
註意: set集合中的元素必須是可hash的, 但是set本?是不可hash得.set是可變的.
set1 = {‘1‘,‘alex‘,2,True,[1,2,3]} # 報錯 set2 = {‘1‘,‘alex‘,2,True,{1:2}} # 報錯 set3 = {‘1‘,‘alex‘,2,True,(1,2,[2,3,4])} # 報錯
set中的元素是不重復的, 且?序的.
s = {"周傑倫", "周傑倫", "周星星"} print(s) 結果: {‘周星星‘, ‘周傑倫‘}
使?這個特性.我們可以使?set來去掉重復
# 給list去重復 lst = [45, 5, "哈哈", 45, ‘哈哈‘, 50] lst = list(set(lst)) # 把list轉換成set, 然後再轉換回list print(lst)
set集合增刪改查
增加
s = {"劉嘉玲", ‘關之琳‘, "王祖賢"} s.add("鄭裕玲") print(s) s.add("鄭裕玲") # 重復的內容不會被添加到set集合中 print(s) s = {"劉嘉玲", ‘關之琳‘, "王祖賢"} s.update("麻花藤") # 叠代更新 print(s) s.update(["張曼?", "李若彤","李若彤"]) print(s)
刪除
s = {"劉嘉玲", ‘關之琳‘, "王祖賢","張曼?", "李若彤"} item = s.pop() # 隨機彈出?個. print(s) print(item) s.remove("關之琳") # 直接刪除元素 # s.remove("??疼") # 不存在這個元素. 刪除會報錯 print(s) s.clear() # 清空set集合.需要註意的是set集合如果是空的. 打印出來是set() 因為要和 dict區分的. print(s) # set()
修改
# set集合中的數據沒有索引. 也沒有辦法去定位?個元素. 所以沒有辦法進?直接修改. # 我們可以采?先刪除後添加的?式來完成修改操作 s = {"劉嘉玲", ‘關之琳‘, "王祖賢","張曼?", "李若彤"} # 把劉嘉玲改成趙本? s.remove("劉嘉玲") s.add("趙本?") print(s)
查詢
# set是?個可叠代對象. 所以可以進?for循環 for el in s: print(el)
常?操作
s1 = {"劉能", "趙四", "???"} s2 = {"劉科?", "馮鄉?", "???"} # 交集 # 兩個集合中的共有元素 print(s1 & s2) # {‘???‘} print(s1.intersection(s2)) # {‘???‘} # 並集 print(s1 | s2) # {‘劉科?‘, ‘馮鄉?‘, ‘趙四‘, ‘???‘, ‘劉能‘} print(s1.union(s2)) # {‘劉科?‘, ‘馮鄉?‘, ‘趙四‘, ‘???‘, ‘劉能‘} # 差集 print(s1 - s2) # {‘趙四‘, ‘劉能‘} 得到第?個中單獨存在的 print(s1.difference(s2)) # {‘趙四‘, ‘劉能‘} # 反交集 print(s1 ^ s2) # 兩個集合中單獨存在的數據 {‘馮鄉?‘, ‘劉能‘, ‘劉科?‘, ‘趙四‘} print(s1.symmetric_difference(s2)) # {‘馮鄉?‘, ‘劉能‘, ‘劉科?‘, ‘趙四‘} s1 = {"劉能", "趙四"} s2 = {"劉能", "趙四", "???"} # ?集 print(s1 < s2) # set1是set2的?集嗎? True print(s1.issubset(s2)) # 超集 print(s1 > s2) # set1是set2的超集嗎? False print(s1.issuperset(s2))
set集合本?是可以發?改變的. 是不可hash的. 我們可以使?frozenset來保存數據. frozenset是不可變的. 也就是?個可哈希的數據類型
s = frozenset(["趙本?", "劉能", "???", "?跪"]) dic = {s:‘123‘} # 可以正常使?了 print(dic)
這個不是很常?. 了解?下就可以了
萬惡之源 - Python基礎數據類型三