[TOC]
# dict字典{}
**無序的對象集合**
其他語言中也稱為map,使用鍵-值(key-value)存儲,具有極快的查找速度。
一個“名字”-“成績”的對照表,直接根據名字查找成績,無論這個表有多大,查找速度都不會變慢
~~~
>>> d = {'Michael': 95, 'Bob': 75, 'Tracy': 85}
>>> d['Michael']
95
~~~
為什么dict查找速度這么快?因為dict的實現原理和查字典是一樣的。假設字典包含了1萬個漢字,我們要查某一個字,一個辦法是把字典從第一頁往后翻,直到找到我們想要的字為止,這種方法就是在list中查找元素的方法,list越大,查找越慢。
第二種方法是先在字典的索引表里(比如部首表)查這個字對應的頁碼,然后直接翻到該頁,找到這個字。無論找哪個字,這種查找速度都非常快,不會隨著字典大小的增加而變慢。
dict就是第二種實現方式,給定一個名字,比如'Michael',dict在內部就可以直接計算出Michael對應的存放成績的“頁碼”,也就是95這個數字存放的內存地址,直接取出來,所以速度非常快。
key-value存儲方式,在放進去的時候,必須根據key算出value的存放位置,這樣,取的時候才能根據key直接拿到value
## 增
把數據放入dict的方法,除了初始化時指定外,還可以通過key放入:
~~~
>>> d['Adam'] = 67
>>> d['Adam']
67
~~~
**setdefault()方法**
此方法是根據函數對字典進行增添元素,參數為(‘key’,‘value’) value默認為none
與直接用 dict[key] = value 的添加元素方法不同,用setdefault(key,value)方法的時候,如果字典沒有該key的時候,則會正常添加,如果已經有了該key,那么將不進行操作(不會覆蓋原來的值)
~~~
dic = {'name': 'jdxia', 'age': 17}
dic.setdefault('name', 'x')
dic.setdefault('a', 'b')
print(dic) # {'name': 'jdxia', 'age': 17, 'a': 'b'}
~~~
## 改
由于一個key只能對應一個value,多次對一個key放入value,后面的值會把前面的值沖掉
~~~
>>> d['Jack'] = 90
>>> d['Jack']
90
~~~
~~~
>>> d['Jack'] = 88
>>> d['Jack']
88
~~~
如果key不存在,dict就會報錯:
~~~
>>> d['Thomas']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'Thomas'
~~~
**update({key:value})方法**
該方法是用來追加、拓展原字典元素。
參數必須為一個字典,如下:
~~~
dic = {'name': 'jdxia', 'age': 17}
dic.update({'addr': 'a'})
~~~
如果傳入的字典里有部分key與原字典相同,則該key所對應的值會被覆蓋,其他沒有的key則會被添加
## 查
要避免key不存在的錯誤,有兩種辦法
**一是通過in判斷key是否存在**
~~~
>>> 'Thomas' in d
False
~~~
**二是通過dict提供的get()方法,如果key不存在,可以返回None,或者自己指定的value**
~~~
>>> d.get('Thomas')
>>> d.get('Thomas', -1)
-1
~~~
注意:返回None的時候Python的交互環境不顯示結果
**len()測量字典中,鍵值對的個數**

**keys返回一個包含字典所有KEY的列表**

**values返回一個包含字典所有value的列表**

**items返回一個包含所有(鍵,值)元祖的列表**

**has_key dict.has_key(key)如果key在字典中,返回True,否則返回False**

## 刪
**pop(key)**
與列表的pop()方法不同,字典的pop()方法必須得給它傳一個key值,如果字典里沒有該key,則會報錯。
也可以用 pop(key,'返回值') 來指定返回值,此時,當找不到key的時候,則不會報錯,會將指定的返回值返回
刪除一個key,用pop(key)方法,對應的value也會從dict中刪除
~~~
>>> d.pop('Bob')
75
>>> d
{'Michael': 95, 'Tracy': 85}
~~~
popitem()方法:
此方法類似于列表的pop()方法,用來隨機刪除一個元素,返回刪除的那個元素的(健,值)
**del**
刪除指定的元素
~~~
info = {'name':'班長', 'sex':'f', 'address':'地球亞洲中國北京'}
print('刪除前,%s'%info['name'])
del info['name']
print('刪除后,%s'%info['name'])
~~~
刪除整個字典
~~~
info = {'name':'monitor', 'sex':'f', 'address':'China'}
print('刪除前,%s'%info)
del info
print('刪除后,%s'%info)
~~~
**clear清空整個字典**
~~~
info = {'name':'monitor', 'sex':'f', 'address':'China'}
print('清空前,%s'%info)
info.clear()
print('清空后,%s'%info)
~~~
## 遍歷

~~~
d = {'a': '1', 'b': '2', 'c': '3'}
for k, v in d.items():
# 這種拼接要2邊都是字符串
s = k + '---' + v
print(s)
~~~
## 注意
**dict內部存放的順序和key放入的順序是沒有關系的**
和list比較,dict有以下幾個特點:
1. 查找和插入的速度極快,不會隨著key的增加而變慢;
2. 需要占用大量的內存,內存浪費多。
而list相反:
1. 查找和插入的時間隨著元素的增加而增加;
2. 占用空間小,浪費內存很少。
所以,dict是用空間來換取時間的一種方法。
dict可以用在需要高速查找的很多地方,需要牢記的第一條就是**dict的key必須是不可變對象**
這是因為dict根據key來計算value的存儲位置,如果每次計算相同的key得出的結果不同,那dict內部就完全混亂了。這個通過key計算位置的算法稱為哈希算法(Hash)。
要保證hash的正確性,作為key的對象就不能變。在Python中,字符串、整數等都是不可變的,因此,可以放心地作為key。而**list是可變的,就不能作為key**:
~~~
>>> key = [1, 2, 3]
>>> d[key] = 'a list'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
~~~
# set集合{}
set和dict類似,也是一組key的集合,但不存儲value。由于key不能重復,所以,在set中,沒有重復的key。
## 增
**創建一個set**
~~~
>>> s = set([1, 2, 3])
>>> s
{1, 2, 3}
~~~
注意,傳入的參數`[1, 2, 3]`是一個list,而顯示的`{1, 2, 3}`只是告訴你這個set內部有1,2,3這3個元素,顯示的順序也不表示set是有序的。。
重復元素在set中自動被過濾:
~~~
>>> s = set([1, 1, 2, 2, 3, 3])
>>> s
{1, 2, 3}
~~~
~~~
set1 = set({1,2,3,4,5})
set2 = {1,2,3,4,5}
set3 = set('abc')
print(set1,set2,set3) #{1, 2, 3, 4, 5} {1, 2, 3, 4, 5} {'c', 'b', 'a'}
~~~
~~~
info = set({"abc": 1, 'a': 2, "cc": "ss"})
print(info)
{'a', 'cc', 'abc'}
~~~
**add(key)**
通過add(key)方法可以添加元素到set中,可以重復添加,但不會有效果:
~~~
>>> s.add(4)
>>> s
{1, 2, 3, 4}
>>> s.add(4)
>>> s
{1, 2, 3, 4}
~~~
**update( )方法**
此方法是用來迭代的往集合里添加元素
~~~
set1 = {1,2,3,4,5}
set1.update('6') #不能直接添加數字類型,因為數字類型不可迭代
print(set1) # {1, 2, 3, 4, 5, '6'}
set1.update('abc')
print(set1) #{1, 2, 3, 4, 5, 'c', 'a', '6', 'b'}
set1.update([1,7,8,9])
print(set1) #{1, 2, 3, 4, 5, 'b', 7, 8, 9, 'a', 'c', '6'}
~~~
## 刪
**remove(key)**
通過remove(key)方法可以刪除元素:
~~~
>>> s.remove(4)
>>> s
{1, 2, 3}
~~~
~~~
set1.remove('2') #指定刪除一個元素,找不到就會報錯
~~~
**pop**
~~~
set1 = {1,2,3,4,5}
set1.pop() #隨機刪除一個元素,將元素值返回
~~~
**clear**
~~~
set1.clear() #清空整個集合
~~~
**del**
~~~
del set1 #刪除整個集合
~~~
**discard**
刪除元素 如果元素不存在,不會做任何操作 也不會報錯
~~~
s.discard('李四')
~~~
## 查
**for循環**
~~~
set1 = {1,2,3,4,5}
for s in set1:
print(s)
#結果如下:
# 1
# 2
# 3
# 4
# 5
~~~
## frozenset( )不可變集合
無法添加無法修改
~~~
set1 = {1,2,3,4,5}
set2 = frozenset(set1)
print(set2,type(set2))
#結果為:frozenset({1, 2, 3, 4, 5}) <class 'frozenset'>
#創建方法如下:
set3 = frozenset({1,2,3})
print(set3) # frozenset({1, 2, 3})
set4 = frozenset('abc') #迭代添加
print(set4) # frozenset({'a', 'b', 'c'})
~~~
## 集合的交并集操作

**交集、并集**
set可以看成數學意義上的無序和無重復元素的集合,因此,兩個set可以做數學意義上的交集、并集等操作:
* s1.union(s2) 并集
* s1.intersection(s2) 交集
~~~
set1 = {1,2,3,7,8}
set2 = {2,3,6,9}
print(set1&set2) #交集{2, 3}
print(set1|set2) #并集{1, 2, 3, 6, 7, 8, 9}
print(set1^set2) #反交集{1, 6, 7, 8, 9},就是交集之外的
print(set1-set2) #差集{8, 1, 7} 獨有的
print(set2-set1) #差集{9, 6} 獨有的
set1 = {1,2,3} #set1為set2的子集
set2 = {1,2,3,4,5} #set2為set1的超集
print(set1 < set2) #判斷一個集合是否為另一個集合的子集,用' < '判斷 如果是,返回:True
~~~
set和dict的唯一區別僅在于沒有存儲對應的value,但是,set的原理和dict一樣,
所以,同樣**不可以放入可變對象**,
因為無法判斷兩個可變對象是否相等,也就無法保證set內部“不會有重復元素”。
試試把list放入set,看看是否會報錯
**子集和超集**
* s1.issubset(s2) s1是否是s2的子集
* s2.issuperset(s1) s2是否是s1的超集
**差集**
* s1.difference(s2)
**異或**
* s1.symmetric_difference(s2)
* `s1.symmetric_difference_update(s2)` 更新s1為異或的結果
# copy( )與 deepcopy()
這兩種方法用于復制一個變量然后賦值給另一個變量。
copy( )----淺復制
簡單來講,用此方法復制后的變量與原變量對應的內存地址是不一樣的,修改它第一層的元素,另一個變量不會被修改
但是如果他們有嵌套(如列表里嵌套列表),那么第二層嵌套的列表與另一個變量所對應的列表的地址就是一個內存地址了,
這個時候,如果修改第二層的元素,則另一個變量也會被修改
用法:
~~~
a = ['a','b','c']
b = a.copy()
print(b)
#結果為:['a', 'b', 'c']
~~~
他們的內存地是不同的,更改一個列表的第一層元素的值,另一個不會被更改,如下:
~~~
li1 = [1,2,[3,4],5]
li2 = li1.copy()
print(li1 is li2) #False
li2[0] = 0 #更改li2第一層的值,li1不會被修改
print(li1) #[1, 2, [3, 4], 5]
~~~
但是,如果我們要修改一個列表的第二層元素的話,另一個列表就會被修改了,如下:
~~~
li1 = [1,2,[3,4],5]
li2 = li1.copy()
print(li1 is li2) #False
li2[2][0] = 0 #更改li2第二層的值,li1就會被修改
print(li1) #[1, 2, [0, 4], 5]
~~~
**deepcopy( )----深復制**
~~~
import copy
li1 = [1,2,[3,4],5]
li2 = copy.deepcopy(li1)
print(li1 is li2) #False
li2[2][0] = 0 #更改li2第二層的值,li1也不會被修改
print(li1) #[1, 2, [3, 4], 5]
~~~
- python入門
- 軟件安裝
- anaconda使用
- py解釋器
- 數據類型和變量
- 編碼
- 字符串
- 格式化
- 數據類型
- 運算符
- list和tuple
- 列表生成式
- dict和set
- 切片和迭代
- set,list,tuple之間互換
- is和==
- 公共方法
- 反射操作
- 數學運算
- 類型轉換
- 對象操作
- 序列操作
- 運算符
- 內置函數
- 交互操作
- 編譯執行
- 引用
- 判斷,循環
- 生成器
- 迭代器
- 函數
- 數據類型轉換
- 空函數
- 參數
- 全局變量
- 返回值
- 遞歸
- 匿名函數
- 文件操作
- 打開和關閉
- 讀寫
- 備份文件
- 文件定位讀寫
- 重命名,刪除
- 文件夾相關操作
- with
- StringIO和BytesIO
- 操作文件和目錄
- 序列化
- 文件屬性
- 面向對象
- 類和對象
- init()方法
- 魔法方法
- 繼承
- 重寫
- 多態
- 類屬性,實例屬性
- 靜態方法和類方法
- 工廠模式
- 單例模式
- 異常
- 私有化
- 獲取對象信息
- *args和**kwargs
- property屬性
- 元類
- slots
- 定制類
- 枚舉
- 模塊
- 模塊介紹
- 模塊中的__name__
- 模塊中的__all__
- 包
- 模塊發布
- 模塊的安裝和使用
- 多模塊開發
- 標準庫
- 給程序傳參數
- 時間
- 正則表達式
- GIL
- 深拷貝和淺拷貝
- 單元測試
- pyqt
- 安裝
- 設置窗口圖標和移動窗口
- 設置氣泡提示和文本
- 圖片展示
- 文本框控件
- 按鈕控件
- 信號和槽
- 布局
- 對話框控件
- pygame
- 窗體關閉事件
- 顯示圖片
- 移動圖片
- 文本顯示
- 背景音和音效
- FPS計算
- surface
- 鼠標事件
- 函數式編程
- map/reduce
- filter
- sorted
- 返回函數
- 裝飾器
- 偏函數
- 網絡編程
- tcp
- udp
- socket
- epoll
- WSGI
- 多任務
- 多線程
- 多進程
- 分布式進程
- 協程
- 迭代器
- 生成器
- yield多任務
- greenlet
- gevent
- ThreadLocal
- asyncio
- async/await
- aiohttp
- 常用內建模塊
- datetime
- collections
- base64
- struct
- hashlib
- hmac
- itertools
- urllib
- xml
- HTMLParser
- 常用第三方模塊
- pillow
- requests
- chardet
- psutil
- 圖形界面
- 海龜繪圖
- Django
- 虛擬環境搭建
- ORM
- 模型類設計和表生成
- 模型類操作
- 關系查詢
- 后臺管理
- 配置mysql
- 字段屬性和選項
- 查詢
- 模型關聯
- 路由
- 模板
- selenium
- 基本原理
- api
- 八種定位方式
- 元素的操作
- 多標簽
- 多表單
- 鼠標,鍵盤
- 警告框
- 下拉框
- 執行js
- 等待
- cookie
- 封裝
- unittest模塊
- 斷言
- 測試用例
- jmeter
- jmeter簡介
- jmeter提取json
- 添加header和cookie
- 讀取csv/txt文件
- 配置文件
- ant