目錄
1 數(shù)據(jù)類型
1.1 整數(shù)
1.2 浮點(diǎn)數(shù)
1.3 字符串
1.4 布爾值
1.5 空值None
1.6 列表list
1.7 元組tuple
1.8 字典dict
1.9 集合set
2 變量
3 不可變對象
4 常量
1 數(shù)據(jù)類型
在Python中,能夠直接處理的數(shù)據(jù)類型有以下幾種:整數(shù)、浮點(diǎn)數(shù)、字符串、布爾值、列表、元組、字典、集合。
1.1 整數(shù)
Python可以處理任意大小的整數(shù),例如:1,100,-80,0,等等。
計算機(jī)由于使用二進(jìn)制,所以有時候用十六進(jìn)制表示整數(shù)比較方便,十六進(jìn)制用0x前綴和0-9,a-f表示,例如:0xff00,0x15a7b4,等等。
1.2 浮點(diǎn)數(shù)
浮點(diǎn)數(shù)也就是小數(shù),之所以稱為浮點(diǎn)數(shù),是因?yàn)榘凑湛茖W(xué)記數(shù)法表示時,一個浮點(diǎn)數(shù)的小數(shù)點(diǎn)位置是可變的,比如,1.23x105和12.3x104是完全相等的。浮點(diǎn)數(shù)可以用數(shù)學(xué)寫法,如1.2,3.141,-7.356,等等。
對于很大或很小的浮點(diǎn)數(shù),必須用科學(xué)計數(shù)法表示,把10用e替代,1.23x105就是1.23e5,或者12.3e8,0.000012可以寫成1.2e-5,等等。
整數(shù)和浮點(diǎn)數(shù)在計算機(jī)內(nèi)部存儲的方式是不同的,整數(shù)運(yùn)算永遠(yuǎn)是精確的,而浮點(diǎn)數(shù)運(yùn)算則可能會有四舍五入的誤差。
1.3 字符串
字符串是以單引號'或雙引號"括起來的任意文本,比如'abc',"xyz"等等。字符串'abc'只有a,b,c這3個字符。
轉(zhuǎn)義字符\可以轉(zhuǎn)義很多字符,比如\n表示換行,\t表示制表符,字符\本身也要轉(zhuǎn)義,所以\表示的字符就是\。
1.4 布爾值
布爾值和布爾代數(shù)的表示完全一致,一個布爾值只有True、False兩種值。在Python中,可以直接用True、False表示布爾值(請注意大小寫),也可以通過布爾運(yùn)算計算出來:
>>> 3 > 2
True
>>> 3 > 5
False
布爾值可以使用and、or和not運(yùn)算。
and運(yùn)算是與運(yùn)算,只有所有都為True,and運(yùn)算結(jié)果才是True:
>>> True and False
False
>>> 3 > 2 and 10 > 9
True
or運(yùn)算是或運(yùn)算,只要其中有一個為True,or運(yùn)算結(jié)果就是True:
>>> True or False
True
>>> False or False
False
not運(yùn)算是非運(yùn)算,它是一個單目運(yùn)算符,把True變成False,F(xiàn)alse變成True:
>>> not True
False
>>> not False
True
>>> not 5 > 2
False
布爾值經(jīng)常用在條件判斷中,比如:
if age >= 18:
print('adult')
else:
print('teenager')
1.5 空值None
空值是Python里一個特殊的值,用None表示。None不能理解為0,因?yàn)?是有意義的,而None是一個特殊的空值。
1.6 列表list
Python內(nèi)置的一種數(shù)據(jù)類型是列表:list。list是一種有序的集合,可以隨時添加和刪除其中的元素。
比如,列出班里所有同學(xué)的名字,就可以用一個list表示:
>>> classmates = ['Michael', 'Bob', 'Tracy']
>>> classmates
['Michael', 'Bob', 'Tracy']
變量classmates就是一個list。用len()函數(shù)可以獲得list元素的個數(shù):
>>> len(classmates)
3
用索引來訪問list中每一個位置的元素,記得索引是從0開始的:
>>> classmates[0]
'Michael'
>>> classmates[3]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: list index out of range
當(dāng)索引超出了范圍時,Python會報一個IndexError錯誤,所以,要確保索引不要越界,記得最后一個元素的索引是len(classmates) - 1。
如果要取最后一個元素,除了計算索引位置外,還可以用-1做索引,直接獲取最后一個元素:
>>> classmates[-1]
'Tracy'
以此類推,可以獲取倒數(shù)第2個、倒數(shù)第3個:
>>> classmates[-2]
'Bob'
>>> classmates[-3]
'Michael'
>>> classmates[-4]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: list index out of range
當(dāng)然,倒數(shù)第4個就越界了。
list是一個可變的有序表,所以,可以往list中追加元素到末尾:
>>> classmates.append('Adam')
>>> classmates
['Michael', 'Bob', 'Tracy', 'Adam']
也可以把元素插入到指定的位置,比如索引號為1的位置:
>>> classmates.insert(1, 'Jack')
>>> classmates
['Michael', 'Jack', 'Bob', 'Tracy', 'Adam']
要刪除list末尾的元素,用pop()方法:
>>> classmates.pop()
'Adam'
>>> classmates
['Michael', 'Jack', 'Bob', 'Tracy']
要刪除指定位置的元素,用pop(i)方法,其中i是索引位置:
>>> classmates.pop(1)
'Jack'
>>> classmates
['Michael', 'Bob', 'Tracy']
要把某個元素替換成別的元素,可以直接賦值給對應(yīng)的索引位置:
>>> classmates[1] = 'Sarah'
>>> classmates
['Michael', 'Sarah', 'Tracy']
list里面的元素的數(shù)據(jù)類型也可以不同,比如:
>>> L = ['Apple', 123, True]
list元素也可以是另一個list,比如:
>>> s = ['python', 'java', ['asp', 'php'], 'scheme']
>>> len(s)
4
要注意s只有4個元素,其中s[2]又是一個list,如果拆開寫就更容易理解了:
>>> p = ['asp', 'php']
>>> s = ['python', 'java', p, 'scheme']
要拿到'php'可以寫p[1]或者s[2][1],因此s可以看成是一個二維數(shù)組,類似的還有三維、四維……數(shù)組,不過很少用到。
如果一個list中一個元素也沒有,就是一個空的list,它的長度為0:
>>> L = []
>>> len(L)
0
1.7 元組tuple
另一種有序列表叫元組:tuple。tuple和list非常類似,但是tuple一旦初始化就不能修改,比如同樣是列出同學(xué)的名字:
>>> classmates = ('Michael', 'Bob', 'Tracy')
現(xiàn)在,classmates這個tuple不能變了,它也沒有append(),insert()這樣的方法。其他獲取元素的方法和list是一樣的,你可以正常地使用classmates[0],classmates[-1],但不能賦值成另外的元素。
不可變的tuple有什么意義?因?yàn)閠uple不可變,所以代碼更安全。如果可能,能用tuple代替list就盡量用tuple。
tuple的陷阱:當(dāng)你定義一個tuple時,在定義的時候,tuple的元素就必須被確定下來,比如:
>>> t = (1, 2)
>>> t
(1, 2)
如果要定義一個空的tuple,可以寫成():
>>> t = ()
>>> t
()
但是,要定義一個只有1個元素的tuple,如果你這么定義:
>>> t = (1)
>>> t
1
定義的不是tuple,是1這個數(shù)!這是因?yàn)槔ㄌ?)既可以表示tuple,又可以表示數(shù)學(xué)公式中的小括號,這就產(chǎn)生了歧義。因此,Python規(guī)定,這種情況下,按小括號進(jìn)行計算,計算結(jié)果自然是1。
所以,只有1個元素的tuple定義時必須加一個逗號,,來消除歧義:
>>> t = (1,)
>>> t
(1,)
Python在顯示只有1個元素的tuple時,也會加一個逗號,,以免你誤解成數(shù)學(xué)計算意義上的括號。
最后來看一個“可變的”tuple:
>>> t = ('a', 'b', ['A', 'B'])
>>> t[2][0] = 'X'
>>> t[2][1] = 'Y'
>>> t
('a', 'b', ['X', 'Y'])
這個tuple定義的時候有3個元素,分別是'a','b'和一個list。不是說tuple一旦定義后就不可變了嗎?怎么后來又變了?
我們先看看定義的時候tuple包含的3個元素:
當(dāng)我們把list的元素'A'和'B'修改為'X'和'Y'后,tuple變?yōu)椋?/p>
表面上看,tuple的元素確實(shí)變了,但其實(shí)變的不是tuple的元素,而是list的元素。tuple一開始指向的list并沒有改成別的list,所以,tuple所謂的“不變”是說,tuple的每個元素,指向永遠(yuǎn)不變。即指向'a',就不能改成指向'b',指向一個list,就不能改成指向其他對象,但指向的這個list本身是可變的!
理解了“指向不變”后,要創(chuàng)建一個內(nèi)容也不變的tuple怎么做?那就必須保證tuple的每一個元素本身也不能變。
1.8 字典dict
Python內(nèi)置了字典:dict的支持,dict全稱dictionary,在其他語言中也稱為map,使用鍵-值(key-value)存儲,具有極快的查找速度。
假設(shè)要根據(jù)同學(xué)的名字查找對應(yīng)的成績,如果用list實(shí)現(xiàn),需要兩個list:
>>> names = ['Michael', 'Bob', 'Tracy']
>>> scores = [95, 75, 85]
給定一個名字,要查找對應(yīng)的成績,就先要在names中找到對應(yīng)的位置,再從scores取出對應(yīng)的成績,list越長,耗時越長。
如果用dict實(shí)現(xiàn),只需要一個“名字”-“成績”的對照表,直接根據(jù)名字查找成績,無論這個表有多大,查找速度都不會變慢。
>>> d = {'Michael': 95, 'Bob': 75, 'Tracy': 85}
>>> d['Michael']
95
為什么dict查找速度這么快?因?yàn)閐ict的實(shí)現(xiàn)原理和查字典是一樣的。假設(shè)字典包含了1萬個漢字,我們要查某一個字,一個辦法是把字典從第一頁往后翻,直到找到我們想要的字為止,這種方法就是在list中查找元素的方法,list越大,查找越慢。
第二種方法是先在字典的索引表里(比如部首表)查這個字對應(yīng)的頁碼,然后直接翻到該頁,找到這個字。無論找哪個字,這種查找速度都非常快,不會隨著字典大小的增加而變慢。
dict就是第二種實(shí)現(xiàn)方式,給定一個名字,比如'Michael',dict在內(nèi)部就可以直接計算出Michael對應(yīng)的存放成績的“頁碼”,也就是95這個數(shù)字存放的內(nèi)存地址,直接取出來,所以速度非常快。
你可以猜到,這種key-value存儲方式,在放進(jìn)去的時候,必須根據(jù)key算出value的存放位置,這樣,取的時候,才能根據(jù)key直接拿到value。
把數(shù)據(jù)放入dict的方法,除了初始化時指定外,還可以通過key放入:
>>> d['Adam'] = 67
>>> d['Adam']
67
由于一個key只能對應(yīng)一個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'
要避免key不存在的錯誤,有兩種辦法,一是通過in判斷key是否存在:
>>> 'Thomas' in d
False
二是通過dict提供的get方法,如果key不存在,可以返回None,或者自己指定的value:
>>> d.get('Thomas')
>>> d.get('Thomas', -1)
-1
注意:返回None的時候Python的交互式命令行不顯示結(jié)果。
要刪除一個key,用pop(key)方法,對應(yīng)的value也會從dict中刪除:
>>> d.pop('Bob')
75
>>> d
{'Michael': 95, 'Tracy': 85}
請務(wù)必注意,dict內(nèi)部存放的順序和key放入的順序是沒有關(guān)系的。
和list比較,dict有以下幾個特點(diǎn):
- 查找和插入的速度極快,不會隨著key的增加而變慢;
- 需要占用大量的內(nèi)存,內(nèi)存浪費(fèi)多。
而list相反:
- 查找和插入的時間隨著元素的增加而增加;
- 占用空間小,浪費(fèi)內(nèi)存很少。
所以,dict是用空間來換取時間的一種方法。
dict可用在需要高速查找的很多地方,正確使用dict需要牢記的第一條就是dict的key必須是不可變對象。
這是因?yàn)閐ict根據(jù)key來計算value的存儲位置,如果每次計算相同的key得出的結(jié)果不同,那dict內(nèi)部就完全混亂了。這個通過key計算位置的算法稱為哈希算法(Hash)。
要保證hash的正確性,作為key的對象就不能變。在Python中,字符串、整數(shù)等都是不可變的,因此,可以放心地作為key。而list是可變的,就不能作為key。
1.9 集合set
set和dict類似,也是一組key的集合,但不存儲value。由于key不能重復(fù),所以,在set中,沒有重復(fù)的key。
要創(chuàng)建一個set,需要提供一個list作為輸入集合:
>>> s = set([1, 2, 3])
>>> s
{1, 2, 3}
注意,傳入的參數(shù)[1, 2, 3]是一個list,而顯示的{1, 2, 3}只是告訴你這個set內(nèi)部有1,2,3這3個元素,顯示的順序也不表示set是有序的。
重復(fù)元素在set中自動被過濾:
>>> s = set([1, 1, 2, 2, 3, 3])
>>> s
{1, 2, 3}
通過add(key)方法可以添加元素到set中,可以重復(fù)添加,但不會有效果:
>>> s.add(4)
>>> s
{1, 2, 3, 4}
>>> s.add(4)
>>> s
{1, 2, 3, 4}
通過remove(key)方法可以刪除元素:
>>> s.remove(4)
>>> s
{1, 2, 3}
set可以看成數(shù)學(xué)意義上的無序和無重復(fù)元素的集合,因此,兩個set可以做數(shù)學(xué)意義上的交集、并集等操作:
>>> s1 = set([1, 2, 3])
>>> s2 = set([2, 3, 4])
>>> s1 & s2
{2, 3}
>>> s1 | s2
{1, 2, 3, 4}
set和dict的唯一區(qū)別僅在于沒有存儲對應(yīng)的value,但是,set的原理和dict一樣,所以,同樣不可以放入可變對象,因?yàn)闊o法判斷兩個可變對象是否相等,也就無法保證set內(nèi)部“不會有重復(fù)元素”。
2 變量
在計算機(jī)程序中,變量不僅可以是數(shù)字,還可以是任意數(shù)據(jù)類型。
變量在程序中就是用一個變量名表示了,變量名必須是大小寫英文、數(shù)字和_的組合,且不能用數(shù)字開頭。
創(chuàng)建對象a = 'ABC'時,Python解釋器干了兩件事情:
- 在內(nèi)存中創(chuàng)建了一個'ABC'的字符串。
- 在內(nèi)存中創(chuàng)建了一個名為a的變量,并把它指向'ABC'。
也可以把一個變量a賦值給另一個變量b,這個操作實(shí)際上是把變量b指向變量a所指向的數(shù)據(jù),例如下面的代碼:
a = 'ABC'
b = a
a = 'XYZ'
print(b)
最后一行打印出變量b的內(nèi)容到底是'ABC'呢還是'XYZ'?如果從數(shù)學(xué)意義上理解,就會錯誤地得出b和a相同,也應(yīng)該是'XYZ',但實(shí)際上b的值是'ABC',讓我們一行一行地執(zhí)行代碼,就可以看到到底發(fā)生了什么事:
執(zhí)行a='ABC',解釋器創(chuàng)建了字符串'ABC'和變量a,并把a(bǔ)指向'ABC':
執(zhí)行b=a,解釋器創(chuàng)建了變量b,并把b指向a指向的字符串'ABC':
執(zhí)行a='XYZ',解釋器創(chuàng)建了字符串'XYZ',并把a(bǔ)的指向改為'XYZ',但b并沒有更改:
所以,最后打印變量b的結(jié)果自然是'ABC'了。
對于可變類型的數(shù)據(jù)來說,賦值語句是在原內(nèi)存地址上進(jìn)行操作的。
對于不可變類型的數(shù)據(jù)來說,賦值語句是重新生成了一個內(nèi)存地址,在新生成的內(nèi)存地址上進(jìn)行操作。
可變類型,值可以改變:
- 列表list
- 字典dict
不可變類型,值不可以改變:
- 數(shù)值類型int,long,bool,float
- 字符串str
- 元組tuple
3 不可變對象
對于可變對象,比如list,對list進(jìn)行操作,list內(nèi)部的內(nèi)容是會變化的,比如:
>>> a = ['c', 'b', 'a']
>>> a.sort()
>>> a
['a', 'b', 'c']
而對于不可變對象,比如str,對str進(jìn)行操作呢:
>>> a = 'abc'
>>> a.replace('a', 'A')
'Abc'
>>> a
'abc'
雖然字符串有個replace()方法,也確實(shí)變出了'Abc',但變量a最后仍是'abc',應(yīng)該怎么理解呢?
我們先把代碼改成下面這樣:
>>> a = 'abc'
>>> b = a.replace('a', 'A')
>>> b
'Abc'
>>> a
'abc'
要始終牢記的是,a是變量,而'abc'才是字符串對象!有些時候,我們經(jīng)常說,對象a的內(nèi)容是'abc',但其實(shí)是指,a本身是一個變量,它指向的對象的內(nèi)容才是'abc':
當(dāng)我們調(diào)用a.replace('a', 'A')時,實(shí)際上調(diào)用方法replace是作用在字符串對象'abc'上的,而這個方法雖然名字叫replace,但卻沒有改變字符串'abc'的內(nèi)容。相反,replace方法創(chuàng)建了一個新字符串'Abc'并返回,如果我們用變量b指向該新字符串,就容易理解了,變量a仍指向原有的字符串'abc',但變量b卻指向新字符串'Abc'了:
所以,對于不變對象來說,調(diào)用對象自身的任意方法,也不會改變該對象自身的內(nèi)容。相反,這些方法會創(chuàng)建新的對象并返回,這樣,就保證了不可變對象本身永遠(yuǎn)是不可變的。
4 常量
常量就是不能變的變量,比如常用的數(shù)學(xué)常數(shù)π就是一個常量。
在Python中,通常用全部大寫的變量名表示常量:PI = 3.14159265359。
但事實(shí)上PI仍然是一個變量,Python根本沒有任何機(jī)制保證PI不會被改變,所以,用全部大寫的變量名表示常量只是一個習(xí)慣上的用法,如果你一定要改變變量PI的值,也沒人能攔住你。
最后解釋一下整數(shù)的除法為什么也是精確的。在Python中,有兩種除法,一種除法是/:
>>> 10 / 3
3.3333333333333335
/除法計算結(jié)果是浮點(diǎn)數(shù),即使是兩個整數(shù)恰好整除,結(jié)果也是浮點(diǎn)數(shù):
>>> 9 / 3
3.0
還有一種除法是//,稱為地板除,兩個整數(shù)的除法仍然是整數(shù):
>>> 10 // 3
3
整數(shù)的地板除//永遠(yuǎn)是整數(shù),即使除不盡。要做精確的除法,使用/就可以。因?yàn)?/除法只取結(jié)果的整數(shù)部分,所以Python還提供一個余數(shù)運(yùn)算,可以得到兩個整數(shù)相除的余數(shù):
>>> 10 % 3
1
無論整數(shù)做//除法還是取余數(shù),結(jié)果永遠(yuǎn)是整數(shù),所以,整數(shù)運(yùn)算結(jié)果永遠(yuǎn)是精確的。
小結(jié)
Python支持多種數(shù)據(jù)類型,在計算機(jī)內(nèi)部,可以把任何數(shù)據(jù)都看成一個“對象”,而變量就是在程序中用來指向這些數(shù)據(jù)對象的,對變量賦值就是把數(shù)據(jù)和變量給關(guān)聯(lián)起來。
注意:Python的整數(shù)沒有大小限制,而某些語言的整數(shù)根據(jù)其存儲長度是有大小限制的,例如Java對32位整數(shù)的范圍限制在-2147483648-2147483647。
Python的浮點(diǎn)數(shù)也沒有大小限制,但是超出一定范圍就直接表示為inf(無限大)。
如果您發(fā)現(xiàn)文中有不清楚或者有問題的地方,請在下方評論區(qū)留言,我會根據(jù)您的評論,更新文中相關(guān)內(nèi)容,謝謝!