1. 程式人生 > >Python基礎資料型別三

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)

這個不是很常⽤. 瞭解⼀下就可以了