變量
可以說(shuō)python只有名字沒(méi)有變量伦籍,不需要定義類型,你賦值啥他就啥類型(所以定義變量時(shí)就得賦值腮出,有int帖鸦、float、str胚嘲、bool
)作儿,甚至可以賦值其他類型,例如:
a=1
a='a'
那么a就從int
變成char
馋劈,這是可以的攻锰,還有就是比如:
>>> 5+3
8 #兩個(gè)int晾嘶,按正常計(jì)算
>>> '5+3'
'5+3' #整個(gè)是str,所以不變
>>> '5'+'3'
'53' #兩個(gè)str娶吞,結(jié)果拼在一起
命名時(shí)可以包括字母垒迂、數(shù)字和下劃線,但不能以數(shù)字開(kāi)頭妒蛇,且大小寫敏感
注:
python作為一門動(dòng)態(tài)語(yǔ)言不需要指明變量類型机断,但這樣也就少了編譯時(shí)檢查錯(cuò)誤的環(huán)境(無(wú)法做類型檢查),只有在運(yùn)行時(shí)才能知道是否存在錯(cuò)誤
變量實(shí)質(zhì)
python當(dāng)中的變量實(shí)際就只是一個(gè)指針绣夺,指向?qū)?yīng)數(shù)據(jù)的地址吏奸,因此python的變量可以隨意修改指向,舉例:
a = 1
print(id(a), id(1))
a = 2
print(id(a), id(1), id(2))
# 會(huì)發(fā)現(xiàn)a只是將指針指向了2
# 1892936144 1892936144
# 1892936176 1892936144 1892936176
在python內(nèi)部有個(gè)intern機(jī)制:將一定范圍內(nèi)的數(shù)或者短的字符串提前載入內(nèi)存陶耍,建立全局唯一的對(duì)象奋蔚,下次再使用時(shí)則直接指向他
e記法
python里計(jì)數(shù)可以用科學(xué)計(jì)數(shù)法,例如0.0002
就可以是2e-4
烈钞,500000
可以是5e5
泊碑,但是e記法的數(shù)一定是浮點(diǎn)數(shù),所以5e5 = 5.0e5 = 500000.0
bool類型
True
就是1棵磷,False
就是0(記住都是首字母大寫)蛾狗,所以可以True * False
(1*0=0),類似這樣仪媒,但是不能True / False
(0不能做分母)沉桌,當(dāng)然這些做法可以,但是不推薦
注:
所有值為0的:0
算吩、0+0j
留凭、0.0
,空字符串''
偎巢、空列表[]
蔼夜、空元組()
、空字典{}
压昼、空集合set()
和None
都是False求冷,其他都是True
強(qiáng)制轉(zhuǎn)型
python支持,例如:a = int(1.666)
窍霞,結(jié)果a為1匠题,其中float轉(zhuǎn)int是將小數(shù)點(diǎn)的數(shù)后直接砍掉。還有其他的強(qiáng)轉(zhuǎn)如下:
#類型轉(zhuǎn)換
float() #轉(zhuǎn)成float
str() #轉(zhuǎn)成str但金,如果是幾種類型混合韭山,其會(huì)用連接符表示,比如:`a = str(ab1)`,就會(huì)變成`'ab+1'`
#進(jìn)制轉(zhuǎn)換
bin() #轉(zhuǎn)二進(jìn)制
oct() #轉(zhuǎn)八進(jìn)制
int() #轉(zhuǎn)十進(jìn)制
hex() #轉(zhuǎn)十六進(jìn)制
對(duì)上面強(qiáng)轉(zhuǎn)舉例:
>>> bin(21)
'0b10101'
>>> type(bin(21))
<class 'str'>
>>> oct(10)
'0o12'
>>> hex(10000)
'0x2710'
可以看出除了十進(jìn)制的钱磅,其他幾種進(jìn)制強(qiáng)轉(zhuǎn)都是前綴加數(shù)字部分梦裂,類型也都是字符串型,所以如果想要只取數(shù)字部分就可以通過(guò)replace()
替換掉前綴
注:
強(qiáng)轉(zhuǎn)時(shí)盖淡,不要有以其命名的變量年柠,例如:
>>> str = 1
>>> str(2)
Traceback (most recent call last):
File "<pyshell#24>", line 1, in <module>
str(2)
TypeError: 'int' object is not callable
可以看出報(bào)錯(cuò)了,說(shuō)str是int類型禁舷,無(wú)法被調(diào)用彪杉,說(shuō)白了就是str已經(jīng)被當(dāng)成前面的變量1了,所以現(xiàn)在只是個(gè)數(shù)字而已(實(shí)際上現(xiàn)在獲取的str是全局空間的牵咙,而不是內(nèi)置空間的str)
python中負(fù)數(shù)的二進(jìn)制展示問(wèn)題:
對(duì)于十進(jìn)制數(shù)據(jù)派近,通過(guò)bin
轉(zhuǎn)成二進(jìn)制時(shí),是直接將其轉(zhuǎn)成正數(shù)的二進(jìn)制加上一個(gè)負(fù)號(hào)洁桌;而對(duì)于十六進(jìn)制通過(guò)bin
轉(zhuǎn)二進(jìn)制時(shí)渴丸,才是返回真正的二進(jìn)制表示,舉例:
>>> bin(-100)
'-0b1100100'
>>> bin(-100 & 0xffffffff)
'0b11111111111111111111111110011100'
參考:https://www.runoob.com/w3cnote/python-negative-storage.html
"""長(zhǎng)字符串"""
像特別長(zhǎng)的字符串甚至有換行另凌,好幾行的那種谱轨,光用'
或者"
引起來(lái)是不行的,此時(shí)可以用頭尾各3個(gè)"
包起來(lái)實(shí)現(xiàn)吠谢,舉例:
"""
這是
一個(gè)
多行
長(zhǎng)字符串
"""
字符串(str)
基本使用
用單引號(hào)或雙引號(hào)包起來(lái)的字符組合土童,但要注意不能單引號(hào)/雙引號(hào)自己給自己嵌套使用,比如下面的用法是不正確的:
'在'單引號(hào)'里面嵌套單引號(hào)'
"在"雙引號(hào)"里面嵌套雙引號(hào)"
所以如果要在字符串中表示單引號(hào)/雙引號(hào)工坊,可以混合著使用献汗,或者使用轉(zhuǎn)義字符,例如下面的方式:
'"雙引號(hào)被單引號(hào)包著"'
"'單引號(hào)被雙引號(hào)包著'"
'使用轉(zhuǎn)義的單引號(hào):\''
其可以幾個(gè)字符用+
連起來(lái)(得都是字符串類型)王污,也可以*
起來(lái)罢吃,舉例:
>>> 'aaa'+ str(2) #+起來(lái)時(shí)要求同種類型
'aaa2'
>>> 'aaa'*2 #*起來(lái)時(shí)不要求為同種類型
'aaaaaa'
開(kāi)頭加r
假如給變量賦值如下:str='c:\now'
,那么在print里輸出時(shí)昭齐,\n
會(huì)被轉(zhuǎn)義尿招,為了避免這種情況,此時(shí)我們可以用\\
替換\
阱驾,這是解決只有少數(shù)地方會(huì)被轉(zhuǎn)義的情況就谜。
但是如果是多路徑比如:'c:\now\abc\ttt'
時(shí),每個(gè)地方都用\\
來(lái)替換會(huì)很麻煩里覆,所以此時(shí)就可以在字符串前面加個(gè)r
丧荐,代表原始字符串,例如:str=r'c:\now\abc\ttt'
租谈,則str就會(huì)自動(dòng)變成c:\\now\\abc\\ttt
,用print輸出時(shí)就是正常的c:\now\abc\ttt
了
開(kāi)頭加u
一般在內(nèi)容為中文時(shí)用,代表內(nèi)容用utf-8編碼的字符串
開(kāi)頭加b
代表字節(jié)類型割去,即byte
類型窟却,字節(jié)流通過(guò)decode(編碼)
來(lái)解碼成字符串,反過(guò)來(lái)字符串通過(guò)encode(編碼)
來(lái)編碼成字節(jié)類型呻逆,舉例:
>>> type(b'abc') //字節(jié)類型
<class 'bytes'>
>>> type(u'abc') //字符串類型
<class 'str'>
>>> type(b'abc'.decode('utf-8')) //字節(jié)流解碼成字符串
<class 'str'>
>>> type(u'abc'.encode('utf-8')) //字符串編碼成字節(jié)流
<class 'bytes'>
分片
可以用分片方法截取字符串的一部分夸赫,例如str1='abcde'
微峰,只取其中abc就可以:str1[:3]
田盈,取'cbce'
就可以:str1='c'+str1[1:3]+'e'
查詢索引
字符串其實(shí)可以看作是一個(gè)特殊的數(shù)組隘击,其每個(gè)字符按順序排放缀程,所以可以像查數(shù)組那樣墓贿,例如上面的str1曙砂,如果:str1[1]
就會(huì)輸出'b'
扳躬,即第二個(gè)字符
通用方法
字符串能使用的方法特別多点楼,像count()
計(jì)數(shù)辐董、index()
索引(find
方法也可以索引悴品,使用跟index一樣,但index找不到會(huì)報(bào)錯(cuò)简烘,find會(huì)返回-1苔严,還有像rfind
方法,是從右邊開(kāi)始查孤澎,很多r開(kāi)頭的都是從右邊開(kāi)始的意思)啥的都能用届氢,參照列表,還有一些常用方法如下:
把第一個(gè)字母改為大寫
str1.capitalize()
把所有字母改為大寫
str1.upper()
將字符串所有內(nèi)容改為小寫
str1.casefold()
將字符串居中
例如我要一個(gè)長(zhǎng)度10的字符串覆旭,然后原來(lái)的字符串內(nèi)容在里面就可以:str1.center(10)
退子,結(jié)果就是' abcde '
;如果要居左就用ljust
姐扮,舉例:
>>> "abc".ljust(10) #居左
'abc '
>>> "abc".rjust(10) #居右
' abc'
指定編碼
str1.encode(encoding='utf-8',error='strict')
表示指定為utf-8編碼絮供,error參數(shù)代表設(shè)置不同錯(cuò)誤的處理方案,默認(rèn)為strict
茶敏,此時(shí)當(dāng)編碼不符是會(huì)報(bào)錯(cuò)壤靶,如果要設(shè)置寬松點(diǎn)的情況可以用ignore
,此時(shí)會(huì)忽略這個(gè)錯(cuò)誤
判斷字符串是否以某子字符串結(jié)束
endswith(sub[,start[,end]])
例如判斷上面str1:str1.endswith('e')
惊搏,因?yàn)槭且?e'結(jié)尾贮乳,所以返回True(判斷'de'、'cde'啥的也是對(duì)的)恬惯,如果判斷是否以某字符串開(kāi)頭用startswith()
把'\t'變成空格
>>> str2='a\tbcd\tc'
>>> str2.expandtabs()
'a(7個(gè)空格)bcd(5個(gè)空格)c'
(因?yàn)槿绻椒ɡ锊惶钊霐?shù)字向拆,默認(rèn)為8個(gè)空格,而tab又是從這個(gè)字符串頭開(kāi)始數(shù)加上空格共8位酪耳,所以a后面加7個(gè)空格浓恳,bcd加5個(gè))
判斷是否為只有字母的非空字符串
str1.isalpha()
結(jié)果返回True或False
判斷是否只有字母或數(shù)字(可以都有)的非空字符串
str1.isalnum()
判斷是否只有數(shù)字的非空字符串
str1.isnumertic()
刹缝,還有isdigit()
都是判斷數(shù)字,但是numertic就算漢字?jǐn)?shù)字比如四也是True颈将,而digit是False梢夯,還有一個(gè)是isdecimal()
三者區(qū)別參考:
http://www.cnblogs.com/jebeljebel/p/4006433.html
判斷字符串是否是標(biāo)題,即字母都以大寫開(kāi)始晴圾,其余位均小寫
>>> str1='Abc'
>>> str2='AbC'
>>> str1.istitle()
True
>>> str2.istitle() #(要把字符串變標(biāo)題形式就用title())
False
>>>
以sub做分隔符插入到字符
str1.join()
颂砸,舉例:
>>> str1='abc'
>>> str1.join('123')
'1abc2abc3'
替換字符串
str1.replace()
,舉例:
>>> str1='abcabcabc'
>>> str1.replace('b','d',2)
'adcadcabc'
對(duì)于其參數(shù)死姚,第一個(gè)是要替換的字符人乓,第二個(gè)是替換成的,第三個(gè)是最多替換幾個(gè)(第三個(gè)參數(shù)可選都毒,默認(rèn)全部替換)
分割字符串
str1.split()
色罚,舉例:
>>> str1='i love you' #第二個(gè)中間有3個(gè)空格
>>> str1.split() #按1到多個(gè)空格分割
['i', 'love', 'you']
>>> str1.split(' ') #按單個(gè)空格分割
['i', 'love', '', '', 'you']
>>> str1.split('i')
['', ' love you']
括號(hào)是選擇按什么字符串分割,默認(rèn)是空格(1到多個(gè))温鸽,比如括號(hào)里是'i'保屯,結(jié)果就是['',' love you'],'i'被切了涤垫,左邊是空字符串
注:
split
還有第二個(gè)參數(shù)姑尺,代表從左到右對(duì)前幾個(gè)指定字符進(jìn)行分割,舉例:
>>> a = "x.y.z.k.q"
>>> a.split('.')
# 默認(rèn)對(duì)所有.都分割
['x', 'y', 'z', 'k', 'q']
>>> a.split('.', 1)
# 只對(duì)從左到右第一個(gè)點(diǎn)分割
['x', 'y.z.k.q']
>>> a.split('.', 2)
# 只對(duì)從左到右第二個(gè)點(diǎn)分割
['x', 'y', 'z.k.q']
同理從右到左可以用rsplit
方法實(shí)現(xiàn)
按行切割
split
會(huì)對(duì)一到多個(gè)空格蝠猬、縮進(jìn)切蟋,以及換行等都進(jìn)行切割,但splitlines
只會(huì)根據(jù)行來(lái)切割榆芦,舉例:
>>> a = """sda s
dsadas
gdfgd"""
>>>
>>> a.split()
# 可以看到空格和行的都被切割了
['sda', 's', 'dsadas', 'gdfgd']
>>> a.splitlines()
# 可以看到僅按行切割
['sda s', 'dsadas', 'gdfgd']
刪除字符串前面或后面的所有某一個(gè)字符串
str1.strip()
柄粹,舉例:
>>> str1='abacaa'
>>> str1.strip('a')
'bac'
只會(huì)刪除前面和后面,中間不管匆绣,括號(hào)里沒(méi)東西默認(rèn)刪空格驻右,如果只要?jiǎng)h除左邊的某些字符就用:lstrip()
,右邊就用rstrip()
崎淳,可以疊加使用堪夭,比如:
>>> str1='abacaa'
>>> str1.strip('a').rstrip('c')
'ba'
翻轉(zhuǎn)字符串大小寫
str1.swapcase()
,舉例:
>>> str1='aBc'
>>> str1.swapcase()
'AbC'
翻轉(zhuǎn)字符串內(nèi)容
常用的方法有分片拣凹、列表翻轉(zhuǎn)后轉(zhuǎn)字符串森爽、循環(huán),舉例:
#分片
>>> a = 'abcde'
>>> a[::-1]
'edcba'
#列表翻轉(zhuǎn)字符串
>>> b = list(reversed(a))
>>> "".join(b)
'edcba'
#for循環(huán)就不舉例了嚣镜,就列表翻轉(zhuǎn)然后一一遍歷相加
更多字符串方法參考
http://bbs.fishc.com/thread-38992-1-1.html
列表(list)
創(chuàng)建一個(gè)空列表:
empty=[]
不像數(shù)組必須都得存放同一種數(shù)據(jù)爬迟,列表里面可以放各種數(shù)據(jù)類型,例如:
user = [123 ,'abc' ,'用戶1' ,[1,2,3,4]]
其中列表內(nèi)每個(gè)對(duì)應(yīng)下標(biāo)為從0開(kāi)始菊匿,但比較特殊的是比如上面的user[3]是一個(gè)列表:[1,2,3,4]付呕,所以如果要定位到4的下標(biāo)就用user[3][3]
计福,即以二維數(shù)組的方式
添加元素
append()方法
例如對(duì)上面的user:user.append('新用戶')
,這個(gè)就會(huì)被加到列表的最后一個(gè)徽职,因?yàn)樵谧詈笠晃话羲眩钥梢酝ㄟ^(guò)user[-1]
查看。要注意append只能加一個(gè)參數(shù)
extend()方法
想要加多個(gè)參數(shù)時(shí)可以用extend()
方法活箕,但是注意extend()也只能傳一個(gè)參數(shù),不過(guò)他可以傳一個(gè)列表參數(shù)(其實(shí)是迭代器可款,但是可以先當(dāng)成是一個(gè)列表)育韩,其原理就是把傳過(guò)去的列表內(nèi)容分別加到后面,從而傳進(jìn)多個(gè)參數(shù)闺鲸,例如對(duì)上面的user: user.extend(['a','b'])
筋讨,結(jié)果就添加了'a'和'b'進(jìn)去
注意要以列表形式傳多個(gè)參數(shù),如果直接傳多個(gè)參數(shù)摸恍,比如extend('a','b')
就會(huì)報(bào)錯(cuò)
注:
append()
也能傳列表悉罕,但和extend()
不同,extend是默認(rèn)傳入列表立镶,所以會(huì)依次把列表里的參數(shù)傳進(jìn)去壁袄;而append傳列表時(shí)就是單純的傳一個(gè)列表進(jìn)去,比如前面通過(guò)兩種方法傳['a','b']媚媒,在extend里傳入的是'a'和'b'嗜逻,在append里傳入的是['a','b']
insert()方法
想要傳到自己想要的位置時(shí)可以用insert()
方法,例如想傳字符串'c'到上面user列表的第二個(gè)位置:user.insert(1,'c')
缭召,其編號(hào)也是從0開(kāi)始的
注:
當(dāng)對(duì)列表使用+
或者+=
(兩種方法實(shí)質(zhì)是有區(qū)別的)時(shí)也可以添加元素栈顷,+
操作算是新建一個(gè)新的列表并添加元素,而不是對(duì)原來(lái)列表添加元素嵌巷,所以原來(lái)的列表并不會(huì)發(fā)生改變萄凤,而+=
是在原來(lái)的列表里添加元素,所以效率上比+
要高些搪哪,舉例:
>>> a = [1,2,3]
>>> b = a + [4] #新建一個(gè)列表b存放a和[4]相加的列表
>>> b
[1, 2, 3, 4]
>>> a #a并沒(méi)有發(fā)生改變
[1, 2, 3]
>>> a = [1,2,3]
>>> a += [4]
>>> a
[1, 2, 3, 4]
注2:
幾種添加元素效率比對(duì)(一般情況下):+
<insert
<extend
<append
<+=
調(diào)換元素
拿上面user對(duì)調(diào)第一第二個(gè)元素舉例:
temp=user[0]
user[0]=user[1]
user[1]=temp
當(dāng)然python里還可以支持更精簡(jiǎn)的寫法:
user[0], user[1] = user[1], user[0]
結(jié)果和前面是一樣的靡努,還有就是可以用列表分片方法來(lái)替換元素,參考下面的列表分片
刪除元素
remove()方法
按變量名刪除噩死,例如:user.remove('abc')
颤难,如果有同名的變量就只刪除第一個(gè),如果想把某個(gè)同名元素全部刪除已维,可以循環(huán)判斷當(dāng)存在某個(gè)元素時(shí)則刪除該元素行嗤,舉例:
while "abc" in user:
li_safe_content.remove("abc")
del函數(shù)
按其下標(biāo)位置刪除,例如刪除user的第一個(gè)變量:del user[1]
垛耳,del后面加變量名甚至可以刪除整個(gè)變量栅屏,例如:del user
就會(huì)把整個(gè)user列表刪了
pop()方法
其會(huì)彈出一個(gè)元素(和刪除有點(diǎn)區(qū)別飘千,其在刪除元素的基礎(chǔ)上,還會(huì)將該元素作為返回值輸出)栈雳,例如:user.pop(1)
护奈,就會(huì)刪除列表的第2個(gè)元素(如果括號(hào)里沒(méi)數(shù)字就默認(rèn)彈出最后一個(gè)),并輸出哥纫,我們可以把這個(gè)給賦值存儲(chǔ)以備后面要用霉旗,例如:temp = user.pop()
,此時(shí)刪除最后一個(gè)值并賦值給temp
刪除重復(fù)元素
可以使用numpy
模塊下的unique()
方法蛀骇,然后再用list()
方法轉(zhuǎn)成列表厌秒,也可以用set()
方法轉(zhuǎn)成集合后再轉(zhuǎn)回來(lái),舉例:
>>> a = [1,2,3,1,2,1]
>>> list(set(a))
[1, 2, 3]
列表分片
可以截取列表的一部分擅憔,比如:user[1:3]
說(shuō)明從下標(biāo)為1的截取到下標(biāo)為3的(不包括3)鸵闪,還可以user[:3]
,說(shuō)明從第1個(gè)到下標(biāo)為3的(不包括3)暑诸,user[:]
說(shuō)明截全部蚌讼,user[:-2]
說(shuō)明截取去掉最后兩個(gè)數(shù)據(jù)后的列表;其還有第三個(gè)可選參數(shù)个榕,意思是變化量篡石,舉例:
>>> d = [1,3,4,5,8]
>>> d[:4:2] #截取從第一個(gè)到第4個(gè),每次跨兩步(隔一個(gè))取
[1, 4]
>>> d[::-1] #截取整個(gè)列表西采,變化量為-1夏志,即取倒過(guò)來(lái)的列表
[8, 5, 4, 3, 1]
切片還可以迭代(連續(xù))切片,舉例:
>>> d = [1,3,4,5,8]
>>> d[1:4][1:] #先切出2到4個(gè)([3,4,5])苛让,然后再切2到后面的所有
[4, 5]
>>> b = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
>>> b[1:][1] [3] #先切出2到后面([[5, 6, 7, 8], [9, 10, 11, 12]])沟蔑,然后取第2個(gè)([9, 10, 11, 12])的第4個(gè)
12
上面說(shuō)的通過(guò)列表替換元素方式如下:
>>> a = [1,2,3,4,5]
>>> a[1:3] = [6,6,6,6,6] #把2、3位替換成5個(gè)6
>>> a
[1, 6, 6, 6, 6, 6, 4, 5]
注:
分片一般用來(lái)截取一個(gè)新的列表狱杰,例如:temp = user[1:3]
瘦材,此時(shí)temp就是一個(gè)新列表了,這里要注意下:temp1=user[:]
和temp2=user
雖然看起來(lái)都是復(fù)制整個(gè)user仿畸,但實(shí)際上不一樣食棕,temp1應(yīng)該更像是截取,所以u(píng)ser無(wú)論怎么變化错沽,跟temp1都無(wú)關(guān)簿晓,而temp2更像是直接指向user,所以是和user同步的千埃,user做了什么操作憔儿,temp2也會(huì)跟著改,這也是為什么需要列表分片來(lái)復(fù)制列表的原因之一
邏輯操作
兩個(gè)列表比較大小放可,只比較第一個(gè)元素谒臼,如果第一個(gè)一樣再比第二個(gè)...朝刊;兩個(gè)列表相加就是后一個(gè)的變量加到前一個(gè)的后面;列表還可以和一個(gè)數(shù)相乘蜈缤,就是把列表里的內(nèi)容重復(fù)幾次拾氓,例如:
>>> a=[1,2,3]
>>> a*2
[1,2,3,1,2,3]
注:
在數(shù)據(jù)分析模塊里有數(shù)組概念,其邏輯操作則和C當(dāng)中數(shù)組一樣底哥,兩個(gè)數(shù)組相加就把同一位置的值相加咙鞍,相乘除就把所有值都乘除一定大小
判斷是否在列表
用in
或者not in
(成員關(guān)系操作符),例如a[]里面有1趾徽,所以:1 in a
就會(huì)是True奶陈,但只能判斷第一層,假如a列表為a[2,3,[1,2,3]] 附较,那么判斷結(jié)果就為False,假如這時(shí)還想判斷是否存在1潦俺,可以用:1 in a[2]
拒课,因?yàn)樵诘?個(gè)元素里所以用a[2]
計(jì)算參數(shù)個(gè)數(shù)
用count()
方法,括號(hào)里輸入?yún)?shù)名事示,例如:
>>> a=[1,2,3,1,2]
>>> a.count(1)
2
既然count()
可以計(jì)算列表里某個(gè)元素的數(shù)量早像,那么就可以通過(guò)將其和集合結(jié)合起來(lái),獲取列表每個(gè)數(shù)據(jù)的數(shù)量肖爵,舉例:
li = [3, 9, 3, 2, 5, 6, 7, 3, 2, 3, 3, 3]
dict1 = {}
#用字典來(lái)存儲(chǔ)結(jié)果
for i in set(li):
dict1[i] = li.count(i)
print(dict1)
結(jié)果:
{2: 2, 3: 6, 5: 1, 6: 1, 7: 1, 9: 1}
索引參數(shù)位置
用index()
方法卢鹦,但如果只輸入要查找的變量名就只會(huì)告訴你第一個(gè)該參數(shù)的位置,例如對(duì)上面的a:a.index(2)
輸出就是1劝堪,所以可以在index里再加2個(gè)參數(shù)確定索引的開(kāi)頭和結(jié)尾冀自,例如在第三個(gè)到第五個(gè)之間查2:a.index(2,2,4)
合并列表
在字符串中有split()
來(lái)把字符串分割成列表,所以也有join()
把列表合并成字符串秒啦,相當(dāng)于split()的逆方法熬粗,比如:
>>> a = '-' #中間用a的值隔開(kāi)
>>> b = a.join(['sad', '2', 'gds'])
>>> b
'sad-2-gds'
>>> b.split('-')
['sad', '2', 'gds']
翻轉(zhuǎn)列表
reverse()
方法,舉例:
>>> a=[1,2,3]
>>> a.reverse()
[3,2,1]
列表排序
sort()
方法余境,如果不輸入?yún)?shù)則默認(rèn)從小到大排序(列表內(nèi)容必須為可對(duì)比的類型驻呐,例如列表里同時(shí)存在數(shù)字和字母就會(huì)報(bào)錯(cuò)),舉例:
>>> a=[2,4,3]
>>> a.sort()
[2,3,4]
其實(shí)sort有3個(gè)參數(shù)芳来,即sort(function,key,reverse=False)
含末,function是自己指定的算法,key代表和算法搭配的關(guān)鍵字即舌,第三個(gè)代表是否倒序佣盒,默認(rèn)為False代表不倒序,如果要倒序就改成True顽聂,例如對(duì)b=['s','ac','gdsa']
進(jìn)行按字符串長(zhǎng)度的倒序排序則:b.sort(key=len,reverse=True)
注:
列表翻轉(zhuǎn)和排序只會(huì)對(duì)當(dāng)前列表進(jìn)行操作沼撕,且沒(méi)有返回值宋雏,所以如果想把列表翻轉(zhuǎn)/排序后賦值給另一個(gè)列表要分兩步進(jìn)行,看下面代碼:
>>> a = [2,3,7,5,1]
>>> b = a.sort()
>>> b
#可以看出b是指向空的务豺,并沒(méi)有把a(bǔ)排序后返回傳給b
>>> a
[1, 2, 3, 5, 7]
#但是可以看出a已經(jīng)排好序了
>>> a.reverse()
>>> b = a
>>> b
[7, 5, 3, 2, 1]
#可以看出如果要翻轉(zhuǎn)/排序后賦值磨总,分兩步進(jìn)行就能成功
打亂列表順序
參考random模塊的shuffle()
方法,把列表作為參數(shù)傳入即可笼沥,舉例:
>>> import random
>>> a
[1, 2, 5, 3, 7]
>>> random.shuffle(a)
>>> a
[5, 3, 1, 7, 2]
元組(tuple)
和列表非常像蚪燕,區(qū)別是其內(nèi)容不可修改,所以像排序啥的操作基本都沒(méi)有
特點(diǎn)
- 可迭代
- 不可變
- 可拆包
注:
元組的不可變性是指存放的內(nèi)容地址不可變奔浅,并不是內(nèi)容不可變馆纳,舉例:
content = [1,2,3]
a = (content,4)
print(a)
content.pop()
print(a)
# ([1, 2, 3], 4)
# ([1, 2], 4)
可以看到元組內(nèi)部存放的列表內(nèi)容是可以改變的,但列表的內(nèi)容改變汹桦,列表的內(nèi)存地址并沒(méi)有一起改鲁驶,所以是允許的
與list比較
- 由于不可變,所以其會(huì)作為常量舞骆,在編譯時(shí)就能夠確定內(nèi)容钥弯,因此性能更好
- 由于不可變,因此可以進(jìn)行哈希運(yùn)算(要求元組內(nèi)部的數(shù)據(jù)也是可哈希類型的督禽,例如元組內(nèi)部存放了列表脆霎,那么就不能進(jìn)行哈希運(yùn)算了),也就可以存放到集合或者字典的key當(dāng)中
- 線程安全
定義元組
定義方法是用小括號(hào)狈惫,例如:a=(1,2,3,4,5)
睛蛛,創(chuàng)建一個(gè)空元組:a=()
,但是元組的標(biāo)志性符號(hào)是逗號(hào)不是小括號(hào)胧谈,例如定義:a=(1)
忆肾,用type函數(shù)會(huì)發(fā)現(xiàn)a是int型,而定義:a=1,2,3
菱肖,會(huì)發(fā)現(xiàn)a是元組难菌,所以說(shuō)逗號(hào)才是元組的標(biāo)志,像前面如果想創(chuàng)建只有一個(gè)元素的元組就得后面加個(gè)逗號(hào)蔑滓,例如:a=(1,)
(不用括號(hào)也可以)
查詢?cè)M
和列表查詢一樣郊酒,例如查第二個(gè):a[1]
(就創(chuàng)建時(shí)候用小括號(hào))
注:
除了定義、刪除的語(yǔ)法還有不可修改的規(guī)定和列表不同外键袱,其他的使用方法和列表幾乎相同燎窘,如分片:b=a[1:]
;還有像count()
(計(jì)算出現(xiàn)次數(shù))蹄咖、index()
方法(索引)褐健、in
、not in
和一些邏輯操作符都可以用,參照上面列表用法
更新元組
雖然說(shuō)元組不能修改蚜迅,但是我們可以更新他舵匾,比如在前面的a的第二個(gè)位置插入6,可以這樣:a=a[:1]+(6,)+a[1:]
(這里括號(hào)和逗號(hào)都要在)谁不,這時(shí)候就更新元組了坐梯,這里不是改變,因?yàn)閍被重新賦值了刹帕,已經(jīng)不是原來(lái)的他了(用id(b)
可以發(fā)現(xiàn)地址已變)
刪除元組
一般刪除元組里的內(nèi)容就用分片截取就好了吵血,跟上面的更新差不多,如果要?jiǎng)h除整個(gè)元組就用del
函數(shù)偷溺,例如:del a
注:
上面知道元組的標(biāo)志是逗號(hào)蹋辅,所以(8)
是代表整數(shù)8,(8,)
代表元組8,挫掏,所以如果用8與上面兩個(gè)分別相乘將會(huì)是不同的結(jié)果:
>>> (8)*8
64
>>> (8,)*8
(8,8,8,8,8,8,8,8)
注2:
列表侦另、元組可以同時(shí)給多個(gè)變量同時(shí)賦值,例如:
>>> x = [1,2,3,4,5]
>>> a,b,c,d,e =x
>>> a
1
>>> a,b,c,d,e
(1, 2, 3, 4, 5)
#可以看出此時(shí)a,b,c,d,e就變成對(duì)應(yīng)的1,2,3,4,5了
前提是賦值變量數(shù)和列表/元組數(shù)值量相同
拆包
a = [1,2,3,4]
b, *c, d = a
print(b, c, d)
# 1 [2, 3] 4
集合(set)
如同字面意思尉共,跟數(shù)學(xué)的集合一樣褒傅,里面的數(shù)據(jù)都是唯一的(最主要意義,所以一般用來(lái)去除重復(fù)內(nèi)容)爸邢,而且是無(wú)序的
定義
- 直接用
{}
定義:舉例:num1 = {1,2,3,3,4,2,1}
,因?yàn)橹滴ㄒ荒美ⅲ詎um1為{1, 2, 3, 4} - 用
set()
函數(shù):舉例:set1 = set([1,2,3,3,2,1])
杠河,括號(hào)里面可以是列表、字符串浇辜、元組券敌、字典等
注:
定義一個(gè)空的集合不能用:set1 = {}
,這樣set1的類型是dict
柳洋,所以應(yīng)該用:set1 = set()
添加元素
用add()
方法待诅,例如:num1.add(6)
,就會(huì)加進(jìn)去了熊镣,但只能加一個(gè)數(shù)據(jù)卑雁,而且不能加list、dict等绪囱,可以加tuple
移除元素
用remove()
方法测蹲,例如:num1.remove(1)
,如果刪除的內(nèi)容不存在則會(huì)報(bào)錯(cuò)鬼吵,如果希望刪除的數(shù)據(jù)即使不存在也不會(huì)報(bào)錯(cuò)扣甲,那么可以用discard()
方法
注:
因?yàn)榧蠠o(wú)序,所以無(wú)法索引齿椅,要讀取里面數(shù)據(jù)可以用for一個(gè)個(gè)讀取出來(lái)琉挖,也能用in來(lái)判斷启泣,或者把他變成一個(gè)列表等等
交集
使用intersection()
方法,或者用&
示辈,舉例:
>>> a = {1,2,3,5,7}
>>> b = {2,4,5,6}
>>> a.intersection(b)
{2, 5}
>>> a & b
{2, 5}
并集
使用union()
方法寥茫,或者用|
,舉例:
>>> a = {1,2,3,5,7}
>>> b = {2,4,5,6}
>>> a.union(b)
{1, 2, 3, 4, 5, 6, 7}
>>> b.union(a)
{1, 2, 3, 4, 5, 6, 7}
>>> a | b
{1, 2, 3, 4, 5, 6, 7}
去不同
比如要找出兩個(gè)集合的不同內(nèi)容顽耳,可以將兩個(gè)集合相減坠敷,舉例:
>>> a = {1,2,3,4,5}
>>> b = {1,5,6}
>>> a-b
{2, 3, 4}
#可以看出結(jié)果就是將a中有的減去b中有的剩下的值
這里放上來(lái)一道網(wǎng)申的筆試題,感覺(jué)用集合解決太完美:
現(xiàn)在有一個(gè)數(shù)組射富,其值為從1到10000的連續(xù)增長(zhǎng)的數(shù)字膝迎。出于某次偶然操作,導(dǎo)致這個(gè)數(shù)組中丟失了某三個(gè)元素胰耗,同時(shí)順序被打亂限次,現(xiàn)在需要你用最快的方法找出丟失的這三個(gè)元素,并且將這三個(gè)元素根據(jù)從小到大重新拼接為一個(gè)新數(shù)字柴灯,計(jì)算其除以7的余數(shù)卖漫。 例:丟失的元素為336,10赠群,8435羊始,得到的新數(shù)字為103368435,除以七的余數(shù)為2查描。
輸入描述:
輸入數(shù)據(jù)為一行突委,包含9997個(gè)數(shù)字,空格隔開(kāi)冬三。
輸出描述:
輸出為一行匀油,包含一個(gè)數(shù)字。
這道題最主要的問(wèn)題就是用最快方法找出集合1到1w里面沒(méi)有的3個(gè)數(shù)勾笆,如果用for循環(huán)遞歸一個(gè)個(gè)比對(duì)敌蚜,顯然花的時(shí)間不是一點(diǎn)兩點(diǎn),于是這里就可以用到集合相減找不同來(lái)實(shí)現(xiàn)窝爪,把兩種方式的代碼都放出來(lái)如下:
#用迭代的方式
li = input().split()
li.sort()
li_t = []
for i in range(1,10000):
#一個(gè)個(gè)用if去判斷
if str(i) not in li:
li_t.append(i)
result = ''
for each in li_t:
result += str(each)
print(int(result)%7)
#用集合的方式
li = set(input().split())
li2 = set(str(i) for i in range(1,10000))
#創(chuàng)建一個(gè)1到10000的集合然后和輸入的集合相減弛车,瞬間就得到那3個(gè)沒(méi)有的了
li_result = list(li2 - li)
li_result.sort()
result = ''
for each in li_result:
result += each
print(int(result)%7)
最終雖然兩個(gè)都能實(shí)現(xiàn),但是迭代花的時(shí)間確是集合的幾十倍蒲每,所以可以看出集合在某些場(chǎng)景下應(yīng)用的強(qiáng)大能力
更多集合操作參考
https://www.cnblogs.com/sunyang945/p/7859962.html
不可變集合(frozenset)
相當(dāng)于集合和元組的集合帅韧,不可變。通過(guò)frozenset()
函數(shù)定義啃勉,舉例:set2 = frozenset([1,2,3,3,2,1])
更多參考
https://blog.csdn.net/weixin_37887248/article/details/81565468
字典(dict)
定義
(1)用{}
定義忽舟,鍵值對(duì)引號(hào)隔開(kāi),例如:dic = {'a':'admin','b':'book','c':'cook'}
,則dic['b']
就是'book'
注:
在python3.6以前的版本當(dāng)中叮阅,字典都是無(wú)序的刁品,如果希望使用有序字典,可以使用collections
下的OrderedDict
類浩姥;而在3.6及以后的版本當(dāng)中挑随,字典都是有序的了
(2)往dict()
中插入元組/列表定義,舉例:
>>> a = [(1,'one'),[2,'two']]
>>> dic1 = dict(a)
>>> dic1
{1: 'one', 2: 'two'}
注:
dict()
能強(qiáng)轉(zhuǎn)成字典類型勒叠,但是str不能直接轉(zhuǎn)成dict兜挨,舉例:
>>> dict("{'a':1,'b':2}")
Traceback (most recent call last):
File "<pyshell#270>", line 1, in <module>
dict("{'a':1,'b':2}")
ValueError: dictionary update sequence element #0 has length 1; 2 is required
所以這時(shí)候可以用eval()
函數(shù)來(lái)轉(zhuǎn)成dict,舉例:
>>> a = eval("{'a':1,'b':2}")
>>> a
{'b': 2, 'a': 1}
>>> type(a)
<class 'dict'>
(3)用dict()
直接指定鍵值對(duì)定義眯分,例如:dic1 = dict(x='abc',y='def')
注:
第三種方式鍵是不加引號(hào)的拌汇,并且關(guān)鍵字會(huì)根據(jù)鍵來(lái)排序,例如:
>>> dic1 = dict(x='abc',y='def',z='ghi')
>>> dic1
{'z': 'ghi', 'x': 'abc', 'y': 'def'}
注2:
像列表弊决、字典等數(shù)據(jù)類型里面還能放像函數(shù)噪舀、類之類的數(shù)據(jù),舉例:
def abc(x, y):
print(x+y)
class XYZ():
def __init__(selt,x):
print(x)
a = 50
a = {'a':1, 'b':abc, 'c':abc(1000,1000), 'd':lambda x,y : print(x+y), 'e': XYZ, 'f': XYZ(10000)}
#b和c都是函數(shù)飘诗,但b沒(méi)傳參數(shù)与倡,c傳了參數(shù),d是沒(méi)傳參的匿名函數(shù)昆稿,e是沒(méi)傳參的類纺座,f是傳參的類
#因?yàn)閏和f都傳了參數(shù),所以調(diào)用時(shí)就已經(jīng)執(zhí)行了溉潭,結(jié)果會(huì)先輸出200和1000净响,但是之后再調(diào)用就不會(huì)執(zhí)行了(其已經(jīng)變成函數(shù)的返回值,這里沒(méi)有岛抄,所以是None)
a['b'](1, 1) #調(diào)用abc函數(shù)别惦,并傳入?yún)?shù)1和2
print(a['c']) #輸出執(zhí)行過(guò)參數(shù)為3和4的abc函數(shù)返回值狈茉,因?yàn)閍bc沒(méi)返回夫椭,所以輸出None
a['d'](5, 5) #調(diào)用lambda函數(shù)
print(a['e'].a) #調(diào)用類XYZ的a屬性
a['e'](100) #調(diào)用類,因?yàn)閭魅肓藚?shù)氯庆,執(zhí)行__init__函數(shù)
結(jié)果為:
2000 #定義a時(shí)第三個(gè)參數(shù)的輸出
10000 #定義a時(shí)最后一個(gè)參數(shù)的輸出
2
None
10
50
100
修改
直接給鍵賦值就好了蹭秋,例如上面的dic1:
>>> dic1['x']='aaa'
{'z': 'ghi', 'x': 'aaa', 'y': 'def'}
如果是不存在的鍵就會(huì)新建這個(gè)鍵值對(duì)
有序字典
默認(rèn)字典是根據(jù)hash之類的原理來(lái)排序的,如果希望字典的順序可以像類似列表那樣按順序排的話堤撵,可以使用OrderedDict
仁讨,具體參考下面鏈接:
http://c.biancheng.net/view/2438.html
內(nèi)置函數(shù)
fromkeys(鍵[,值])
創(chuàng)建并返回一個(gè)統(tǒng)一值的新字典,其中可以設(shè)置鍵和值实昨,舉例:
>>> d1={}
>>> d1.fromkeys((1,2,3)) #創(chuàng)建一個(gè)字典洞豁,并定義3個(gè)鍵1、2、3
{1: None, 2: None, 3: None}
>>> d1.fromkeys((1,2,3),1) #定義3個(gè)鍵并同時(shí)賦值為1
{1: 1, 2: 1, 3: 1}
他只能給所有鍵設(shè)置同一個(gè)值丈挟,所以不要以為可以通過(guò)傳入列表刁卜、元組來(lái)依次賦值,比如:
>>> d1.fromkeys((1,2,3),(4,5,6))
{1: (4, 5, 6), 2: (4, 5, 6), 3: (4, 5, 6)} #結(jié)果不是{1:4, 2:5, 3:6}曙咽,而是值都為(4, 5, 6)
可以看出其還是給所有元素都設(shè)置了同一個(gè)值
keys()
返回字典的所有鍵名蛔趴,例如:
>>> d1={1:2,2:'two'}
>>> d1.keys()
dict_keys([1, 2])
values()
返回字典的所有值,例如:
>>> d1={1:2,2:'two'}
>>> d1.values()
dict_values([2, 'two'])
items()
返回字典的所有鍵值對(duì)例朱,例如:
>>> d1={1:2,2:'two'}
>>> d1.items()
dict_items([(1, 2), (2, 'two')])
注:
keys
孝情、values
、items
常用于循環(huán)輸出字典洒嗤,例如:
for key in d1.keys()
print("循環(huán)輸出所有的鍵:",key)
get()
根據(jù)鍵獲取值箫荡,一般常用d1[鍵]
輸出值,但如果鍵不存在烁竭,這種方法就會(huì)報(bào)錯(cuò)菲茬,所以用get就更寬松,比如對(duì)上面的d1:d1.get(1)
結(jié)果就是2派撕,但是d1.get(3)
不輸出也不會(huì)報(bào)錯(cuò)婉弹,如果用print打印結(jié)果會(huì)是none,我們還可以用get來(lái)判斷輸出终吼,有就輸出值镀赌,沒(méi)有就輸出我們想要的內(nèi)容,比如:
>>> d1.get(3,'nothing')
nothing #因?yàn)?不存在所以輸出nothing际跪,如果3在就輸出3的值
注:
get可以判斷鍵在不在字典商佛,in和not in也可以,比如上面的:1 in d1
結(jié)果就是True
注2:
因?yàn)殒I是唯一的姆打,所以可以用get(鍵)
和dict[鍵]
來(lái)獲取值良姆,反過(guò)來(lái)如果想通過(guò)值來(lái)獲取鍵,可以通過(guò)get條件判斷來(lái)進(jìn)行遍歷,舉例:
>>> d
{2: 2, 3: 6, 5: 1, 6: 1, 7: 1, 9: 1}
>>> [i for i in d if d.get(i) == 1]
#鏈表推導(dǎo)式當(dāng)i(鍵)=1(值)時(shí)勺爱,輸出i
[5, 6, 7, 9]
>>> [i for i in d if d.get(i) == 6]
[3]
如果是要求最值的鍵甲献,則可以用內(nèi)置的min
/max
函數(shù),舉例:
>>> d
{2: 2, 3: 6, 5: 1, 6: 1, 7: 1, 9: 1}
>>> max(d, key=d.get)
3
clear()
清空字典痊剖,例如:d1.clear()
結(jié)果d1就變成{}
注:
d1={}
會(huì)使d1變成空,但是其原來(lái)指向的字典沒(méi)變成空垒玲,而clear才是真正意義上的清空陆馁,例如:
>>> d1={1:2,2:'two'}
>>> d2 = d1 #此時(shí)d2和d1指向同一個(gè)地址,可以用id(d2)查看
>>> d1 = {}
>>> d1 #d1變成空
{}
>>> d2 #d2還是指向d1原來(lái)的地方合愈,而原來(lái)指向的地方?jīng)]變成空叮贩,所以d2沒(méi)變成空
{1: 2, 2: 'two'}
###這次使用clear
>>> d1={1:2,2:'two'}
>>> d2 = d1
>>> d1.clear()
>>> d1
{}
>>> d2 #這次d2和d1一樣都清空了
{}
copy()
淺拷貝击狮,和賦值不太一樣,賦值就相當(dāng)于確定了指向益老,所以用id()
查看會(huì)發(fā)現(xiàn)賦值后原來(lái)的字典和賦值的字典地址是一樣的帘不,但copy的結(jié)果地址是不同的,所以如果原字典內(nèi)容改變杨箭,賦值的字典會(huì)跟著改變寞焙,但copy的字典不變(copy有點(diǎn)像列表里的整個(gè)分段賦值)
pop()
括號(hào)里給定鍵彈出對(duì)應(yīng)的值
popitem()
括號(hào)里沒(méi)參數(shù),隨機(jī)彈出一個(gè)項(xiàng)
setdefault()
跟get
有點(diǎn)像互婿,能輸出鍵對(duì)應(yīng)的值捣郊,但不同的是如果鍵不存在他會(huì)新加進(jìn)去,例如:d1.setdefault(1)
結(jié)果是2慈参,但d1.setdefault(3)
呛牲,結(jié)果d1會(huì)變成:{1: 2, 2: 'two', 3: None} ,新建同時(shí)還可以賦值驮配,例如:d1.setdefault(5,"aaa")
娘扩,d1就會(huì)變成:{1: 2, 2: 'two', 3: None, 5: 'aaa'}
update()
把一個(gè)字典的東西加到另一個(gè)字典里去,例如:
>>> d2={6:'bbb'}
>>> d1.update(d2)
{1: 2, 2: 'two', 3: None, 5: 'aaa', 6: 'bbb'} #加入了d2的內(nèi)容
for輸出
- 方法1:其輸出是只輸出鍵而不是值壮锻,所以如果想輸出值就要輸出字典的對(duì)應(yīng)項(xiàng)琐旁,舉例:
dict1 = {'a':'one','b':'two','c':'three'}
for each in dict1:
print("%s -> %s" % (each,dict1[each]),end=' ') #each只是鍵
結(jié)果為:a -> one b -> two c -> three
- 方法2:通過(guò)將字典放入迭代器,然后分別保存鍵猜绣、值灰殴,舉例:
dict1 = {'a':'one','b':'two','c':'three'}
for key,value in dict1.items(): #分別賦值鍵值到key和value
print(key,value,end=' ')
結(jié)果為:b two a one c three
字典和json區(qū)別
字典和json樣式十分相似,雖然前者是數(shù)據(jù)類型掰邢,后者是一種格式牺陶,但最明顯的區(qū)別就是字典可以用單引號(hào),而在json中得用雙引號(hào)辣之,所以如果想將一個(gè)字典以json格式傳遞時(shí)掰伸,記得將單引號(hào)都替換成雙引號(hào)
Ellipsis
這個(gè)是python一個(gè)自帶常量,和...
是等價(jià)的(偶然輸入...
發(fā)現(xiàn)竟然沒(méi)有報(bào)錯(cuò)怀估,原來(lái)還有內(nèi)置這樣的常量)狮鸭,意思相當(dāng)于什么都沒(méi)有,或者在數(shù)組之類的地方起省略意義奏夫,一般可以和pass
相互替換怕篷,舉例:
>>> ...
Ellipsis
>>> print(...)
Ellipsis
>>> print(Ellipsis)
Ellipsis
字典效率历筝、順序
- 字典的內(nèi)存開(kāi)銷大酗昼,但是查詢快,而自定義的對(duì)象梳猪、以及python提供的對(duì)象也都是用字典來(lái)包裝的
- 在python3.6之前麻削,字典是無(wú)序的蒸痹,因此其存儲(chǔ)順序和元素添加的順序有關(guān)(基于哈希表內(nèi)部的原理,哈希沖突的處理等)呛哟,并且添加數(shù)據(jù)有可能改變已有數(shù)據(jù)的順序(例如哈希表內(nèi)部達(dá)到一定占用率時(shí)會(huì)進(jìn)行擴(kuò)容叠荠,將重新開(kāi)辟空間依次存入,導(dǎo)致順序改變)扫责,所以如果想要使用有序字典榛鼎,可以使用
collections
模塊下的OrderedDict
;python3.6開(kāi)始鳖孤,字典都是有序的了
其他數(shù)據(jù)類型
隊(duì)列(queue)
先入先出者娱,且一個(gè)數(shù)據(jù)只能取一次,需要import queue
苏揣,使用也很簡(jiǎn)單黄鳍,先新建一個(gè)Queue
對(duì)象,然后要往隊(duì)列加?xùn)|西就用put()
平匈,取東西就用get()
就行了(用get如果隊(duì)列為空則會(huì)卡住框沟,所以也可以用get_nowait
,當(dāng)隊(duì)列為空時(shí)會(huì)出異常)增炭,查看用qsize()
忍燥,舉例:
q = queue.Queue() #新建一個(gè)隊(duì)列
q.put("one")
q.put("two")
q.put([1,2,3])
q.qsize() #結(jié)果為3
q.get() #結(jié)果為one
q.get() #結(jié)果為two
q.get() #結(jié)果為[1,2,3]
q.get() #程序卡住,如果是q.get_nowait()則會(huì)報(bào)出空異常
如果想要限制隊(duì)列大小隙姿,可以在新建對(duì)象時(shí)里面加入maxsize
參數(shù)灾前,比如:
q = queue.Queue(maxsize=3)
此時(shí)一旦超過(guò)隊(duì)列長(zhǎng)度就會(huì)卡住,然后查看put和get會(huì)發(fā)現(xiàn)里面都有個(gè)block
(默認(rèn)為True)和timeout
(默認(rèn)為None)參數(shù)孟辑,前者代表是否卡住哎甲,后者代表卡住幾秒,所以我們可以設(shè)置為False或者設(shè)置timeout時(shí)長(zhǎng)來(lái)避免卡住饲嗽,比如:
c.get(block=False) #當(dāng)隊(duì)列為空時(shí)報(bào)錯(cuò)炭玫,不卡住
c.get(timeout=1) #當(dāng)隊(duì)列為空時(shí)延時(shí)一秒,然后報(bào)錯(cuò)
#put方法同理
實(shí)例
(通過(guò)多線程和隊(duì)列實(shí)現(xiàn)生產(chǎn)者消費(fèi)者順序購(gòu)買產(chǎn)品問(wèn)題)
import threading
import time
import queue
def Producer():
count = 1
while True:
q.put("產(chǎn)品%d" % count)
print("\033[42;m生產(chǎn)第%d個(gè)產(chǎn)品\033[0m" % count)
time.sleep(0.3)
count += 1
print("\033[45;m目前還剩%d個(gè)產(chǎn)品\033[0m" % q.qsize())
def Consumer(name):
num = 0
while True:
print("\033[43;m%s購(gòu)買了%s\033[0m" % (name, q.get()))
num += 1
print("\033[45;m%s共買了%d個(gè)產(chǎn)品\033[0m" % (name, num))
time.sleep(1)
q = queue.Queue()
producer = threading.Thread(target=Producer)
consumerA = threading.Thread(target=Consumer, args=("熱心市民A",))
consumerB = threading.Thread(target=Consumer, args=("熱心市民B",))
producer.start()
consumerA.start()
consumerB.start()
棧(stack)
和前面的隊(duì)列十分相似貌虾,也是導(dǎo)入queue
吞加,但是新建的對(duì)象是LifoQueue
,其他和隊(duì)列一樣尽狠,當(dāng)然用列表的append()
和pop()
也可以實(shí)現(xiàn)衔憨。
優(yōu)先級(jí)隊(duì)列
在queue中還有一個(gè)PriorityQueue
是用來(lái)實(shí)現(xiàn)優(yōu)先級(jí)隊(duì)列的,其和上面的區(qū)別就是在put的時(shí)候傳入的是個(gè)元組袄膏,里面同時(shí)設(shè)置優(yōu)先值践图,值越小越優(yōu)先,舉例:
q = queue.PriorityQueue()
q.put((2, "two"))
q.put((5, "five"))
q.put((0, "zero"))
q.put((1, "one"))
q.get() #(0, 'zero')
q.get() #(1, 'one')
q.get() #(2, 'two')
q.get() #(5, 'five')
雙向隊(duì)列
前面的棧和隊(duì)列都是單向的沉馆,一旦定義以后就只能從頭或者尾其中一邊操作码党,在list中雖然可以用pop來(lái)實(shí)現(xiàn)棧的功能德崭,但是卻無(wú)法實(shí)現(xiàn)隊(duì)列的功能,所以這里可以用雙向隊(duì)列揖盘,需要使用到collections
的deque
眉厨,可以直接用from import導(dǎo)入deque,然后通過(guò)append()
兽狭、appendleft()
憾股、pop()
、popleft()
來(lái)實(shí)現(xiàn)棧和隊(duì)列箕慧,舉例:
from collections import deque
a = deque() # deque([])
a.append(5) # deque([5])
a.appendleft(4) # deque([4, 5])
a.appendleft(3) # deque([3, 4, 5])
a.pop() #5
a.popleft() #3
計(jì)數(shù)器
在前面的collections里有個(gè)Counter
還是作為計(jì)數(shù)器的存在荔燎,其可以計(jì)算一個(gè)數(shù)據(jù)結(jié)構(gòu)當(dāng)中各元素出現(xiàn)的次數(shù),并返回一個(gè)字典销钝,需要導(dǎo)入Counter有咨,舉例:
from collections import Counter
c = Counter([1,2,3,32,1,2,1,2,2,3,4])
#計(jì)算該列表里各元素個(gè)數(shù)
print(c)
結(jié)果為:Counter({2: 4, 1: 3, 3: 2, 32: 1, 4: 1})
python內(nèi)置類型
數(shù)值類型
int
float
bool
complex 復(fù)數(shù)類型
迭代類型
iterator 迭代器
generator 生成器
序列類型
list
bytes
bytearray 字節(jié)流,數(shù)據(jù)只能是0或1
memoryview 二進(jìn)制序列
range
tuple
str
array 數(shù)組蒸健,相比于list座享,其所有數(shù)據(jù)必須為同一類型,因此內(nèi)存空間也是連續(xù)的似忧,效率更高
映射
dict
集合
set
frozenset 不可變集合
注:集合和映射在python中的實(shí)現(xiàn)差不多渣叛,因此效率都比較高
上下文管理器
with
其他
模塊類型
類對(duì)象
類實(shí)例
函數(shù)類型
方法類型
代碼類型
object對(duì)象
type類型
ellipsis類型
notimplemented類型
序列類
分類
容器序列:內(nèi)部可以存放任意類型數(shù)據(jù),如list盯捌、tuple淳衙、deque
扁平序列:只能存放相同類型的數(shù)據(jù),如str饺著、array箫攀、bytes、bytearray
可變序列:內(nèi)容可以修改幼衰,如list靴跛、array、deque渡嚣、bytearray
不可變序列:內(nèi)容不能修改梢睛,如tuple、str识椰、bytes
相關(guān)基類
collections.abc
下提供了Sequence
(不可變序列)/MutableSequence
(可變序列)類
+/extend/+=區(qū)別
- +:必須為相同類型绝葡,并且返回一個(gè)新的序列對(duì)象,源碼(基于
UserList
稍作修改):
def __add__(self, other):
return self.__class__(self + self.__class__(other))
- extend:只要是序列類就行腹鹉,也是在原先對(duì)象中改變藏畅,本質(zhì)就是for循環(huán),依次
append
种蘸,源碼:
def extend(self, values):
'S.extend(iterable) -- extend sequence by appending elements from the iterable'
for v in values:
self.append(v)
- +=:只要是序列類就行墓赴,并且在原先的對(duì)象中進(jìn)行改變,內(nèi)部實(shí)際是調(diào)用
extend
方法航瞭,源碼:
def __iadd__(self, values):
self.extend(values)
return self
切片
相關(guān)操作
>>> a = [1,2,3,4,5]
>>> a[2:] = [5,6,7]
# 替換第三個(gè)元素開(kāi)始的后面所有元素
>>> a
[1, 2, 5, 6, 7]
>>> a[:0] = [0]
# 在頭部插入元素
>>> a
[0, 1, 2, 5, 6, 7]
>>> a[2:] = [9, 8, 7]
>>> a
[0, 1, 9, 8, 7]
>>> a[::2] = [10, 20, 30]
# 隔一個(gè)改一個(gè)元素诫硕,右邊迭代的長(zhǎng)度必須和左邊切片的長(zhǎng)度相等
>>> a
[10, 1, 20, 8, 30]
>>> a[:1] = []
# 刪除第一個(gè)元素
>>> a
[1, 20, 8, 30]
>>> del a[::2]
# 隔一個(gè)刪一個(gè)元素
>>> a
[20, 30]
>>> del a[:1]
# 刪除第一個(gè)元素
>>> a
[30]
>>> a[0:0] = [1,2,3]
# 往第0個(gè)位置插入3個(gè)元素
>>> a
[1, 2, 3, 30]
實(shí)現(xiàn)原理
在通過(guò)切片索引時(shí),會(huì)自動(dòng)將切片語(yǔ)法轉(zhuǎn)成slice
對(duì)象刊侯,該對(duì)象包括起始位置章办、結(jié)束位置和步長(zhǎng)三個(gè)參數(shù),舉例:
a = [1,2,3,4,5]
print(a[0::2])
print(a[slice(0, None, 2)])
# [1, 3, 5]
# [1, 3, 5]
可以看出兩個(gè)結(jié)果都是一樣的滨彻,然后對(duì)象只需要實(shí)現(xiàn)__getitem__
方法藕届,在內(nèi)部處理slice
的處理邏輯即可,我們可以自己模擬實(shí)現(xiàn)一個(gè)自己的slice
對(duì)象和相關(guān)的切片處理邏輯亭饵,舉例:
class MySlice:
def __init__(self, start=None, end=None, step=None):
self.start = start
self.end = end
self.step = step
def get_slice(self):
return self.start, self.end, self.step
class Test:
def __init__(self, data=[]):
self.data = data
def __setitem__(self, item, value):
if isinstance(item, MySlice):
start, end, step = self.parse_slice(item)
value = iter(value)
for i in range(start, end, step):
self.data[i] = next(value)
else:
self.data[item] = value
def __getitem__(self, item):
cls = type(self)
if isinstance(item, MySlice):
start, end, step = self.parse_slice(item)
return cls([self.data[i] for i in range(start, end, step)])
# 重新實(shí)例化一個(gè)自身對(duì)象返回
return cls(self.data[item])
def parse_slice(self, s):
"""自定義切片設(shè)置默認(rèn)值"""
start, end, step = s.get_slice()
if start == None:
start = 0
if end == None:
end = len(self.data)
if step == None:
step = 1
return start, end, step
def __str__(self):
return str(self.data)
li = Test([1,2,3,4,5])
sli = MySlice(0, None, 2)
print(li[sli])
li[sli] = [9, 8, 7]
print(li)
# [1, 3, 5]
# [9, 2, 8, 4, 7]
映射類
不可變映射類
MappingProxyType
休偶,繼承于Mapping類,相當(dāng)于一個(gè)只讀的字典辜羊,源碼如下:
MappingProxyType = type(type.__dict__)
我們可以從types
模塊下導(dǎo)入踏兜,使用舉例:
from types import MappingProxyType
di = MappingProxyType({"a":1, "b":2})
print(di)
di["a"] = 2
# 不允許修改,這句會(huì)報(bào)錯(cuò)
可變映射類
dict
八秃,繼承于MutableMapping類碱妆,而該類繼承于Mapping類
UserDict
可以理解為用python實(shí)現(xiàn)的字典,由于python中的列表昔驱、字典都是用C寫的疹尾,內(nèi)部有些魔法方法之類的未必能生效,因此如果希望繼承一個(gè)字典的話骤肛,那么可以繼承collection
模塊下提供的UserDict
(collection
下還提供了UserList
/UserStr
與之同理)纳本,舉例:
from collections import UserDict
class A(dict):
def __setitem__(self, item, value):
super().__setitem__(item, value*2)
class B(UserDict):
def __setitem__(self, item, value):
super().__setitem__(item, value*2)
a = A(x=1)
b = B(x=1)
print(a)
print(b)
# {'x': 1}
# {'x': 2}
可以看到繼承自dict的類,實(shí)例化的對(duì)象的__setitem__
方法沒(méi)生效腋颠,但是繼承自UserDict
的卻生效了
defaultdict
和UserDict
一樣是dict的子類饮醇,初始化時(shí)可以指定當(dāng)索引內(nèi)容不存在時(shí)的默認(rèn)值類型,本質(zhì)是內(nèi)部實(shí)現(xiàn)了__missing__
的魔法方法秕豫,當(dāng)key的值獲取失敗時(shí)朴艰,則會(huì)設(shè)置一個(gè)默認(rèn)類型的值,舉例:
def default():
return {
"name": "aaa",
"age": 18
}
a = defaultdict(default)
# 指定默認(rèn)是一個(gè)固定內(nèi)容的字典混移,傳入的默認(rèn)對(duì)象必須是可調(diào)用的祠墅,這里傳入一個(gè)函數(shù),也可以傳入list歌径、dict等數(shù)據(jù)類型
print(a["x"])
a["y"] = 2
print(a)
# {'name': 'aaa', 'age': 18}
# defaultdict(<function default at 0x00000162E1A33EA0>, {'x': {'name': 'aaa', 'age': 18}, 'y': 2})
可哈希對(duì)象
- 對(duì)于字典的key毁嗦、集合的元素都必須是可哈希的才能存入
- 不可變對(duì)象都是可hash的,如:
str
回铛、fronzeset
狗准、tuple
克锣,如果希望自己定義的類可哈希,那么必須實(shí)現(xiàn)__hash__
的魔法方法
注:
不可變對(duì)象如果是可哈希的腔长,還必須滿足子元素也都是可哈希的條件袭祟,舉例:
print(hash((1,2,3)))
# 元組內(nèi)部維護(hù)的數(shù)字是不可變的,因此可哈希
li = [1,2,3]
print(hash((1,li)))
# 元組內(nèi)部有一個(gè)可變的列表捞附,不可哈希巾乳,因此會(huì)報(bào)錯(cuò)
# 2528502973977326415
# TypeError: unhashable type: 'list'