標籤:python 資料類型
當語句以冒號:結尾時,縮排的語句視為代碼塊。
縮排有利有弊。好處是強迫你寫出格式化的代碼,但沒有規定縮排是幾個空格還是Tab。按照約定俗成的管理,應該始終堅持使用4個空格的縮排。
Python程式是大小寫敏感的,如果寫錯了大小寫,程式會報錯。
資料類型
電腦顧名思義就是可以做數學計算的機器,因此,電腦程式理所當然地可以處理各種數值。但是,電腦能處理的遠不止數值,還可以處理文本、圖形、音頻、視頻、網頁等各種各樣的資料,不同的資料,需要定義不同的資料類型。在Python中,能夠直接處理的資料類型有以下幾種:
資料類型
數字(整形,長整形,浮點型,複數)
字串
列表
元組
字典
集合
整數
Python可以處理任意大小的整數,當然包括負整數,在程式中的表示方法和數學上的寫法一模一樣,例如:1,100,-8080,0,等等。
電腦由於使用二進位,所以,有時候用十六進位表示整數比較方便,十六進位用0x首碼和0-9,a-f表示,例如:0xff00,0xa5b4c3d2,等等。
浮點數
浮點數也就是小數,之所以稱為浮點數,是因為按照科學記號標記法表示時,一個浮點數的小數點位置是可變的,比如,1.23x109和12.3x108是完全相等的。浮點數可以用數學寫法,如1.23,3.14,-9.01,等等。但是對於很大或很小的浮點數,就必須用科學計數法表示,把10用e替代,1.23x109就是1.23e9,或者12.3e8,0.000012可以寫成1.2e-5,等等。
整數和浮點數在電腦內部儲存的方式是不同的,整數運算永遠是精確的(除法難道也是精確的?是的!),而浮點數運算則可能會有四捨五入的誤差。
字串
字串是以單引號‘或雙引號"括起來的任意文本,比如‘abc‘,"xyz"等等。請注意,‘‘或""本身只是一種表示方式,不是字串的一部分,因此,字串‘abc‘只有a,b,c這3個字元。如果‘本身也是一個字元,那就可以用""括起來,比如"I‘m OK"包含的字元是I,‘,m,空格,O,K這6個字元。
如果字串內部既包含‘又包含"怎麼辦?可以用逸出字元\來標識,比如:
‘I\‘m \"OK\"!‘
表示的字串內容是:
I‘m "OK"!
逸出字元\可以轉義很多字元,比如\n表示換行,\t表示定位字元,字元\本身也要轉義,所以\表示的字元就是\,可以在Python的互動式命令列用print()列印字串看看:
print(‘I\‘m ok.‘)
效果:
print(‘I\‘m learning\nPython.‘)
print(‘\\n\‘)
如果字串裡面有很多字元都需要轉義,就需要加很多\,為了簡化,Python還允許用r‘‘表示‘‘內部的字串預設不轉義
print(‘\\t\‘)
print(r‘\\t\‘)
如果字串內部有很多換行,用\n寫在一行裡不好閱讀,為了簡化,Python允許用‘‘‘...‘‘‘的格式表示多行內容
注意在輸入多行內容時,提示符由>>>變為...,提示你可以接著上一行輸入,注意...是提示符,不是代碼的一部分
當輸入完結束符```和括弧)後,執行該語句並列印結果。
如果寫成程式並存為.py檔案,就是:
print(‘‘‘line1
line2
line3‘‘‘)
布爾值
布爾值和布爾代數的表示完全一致,一個布爾值只有True、False兩種值,要麼是True,要麼是False,在Python中,可以直接用True、False表示布爾值(請注意大小寫),也可以通過布爾運算計算出來:
布爾值可以用and、or和not運算。
and運算是與運算,只有所有都為True,and運算結果才是True:
or運算是或運算,只要其中有一個為True,or運算結果就是True:
not運算是非運算,它是一個單目運算子,把True變成False,False變成True:
布爾值經常用在條件判斷中
空值
空值是Python裡一個特殊的值,用None表示。None不能理解為0,因為0是有意義的,而None是一個特殊的空值。
變數
變數的概念基本上和初中代數的方程變數是一致的,只是在電腦程式中,變數不僅可以是數字,還可以是任意資料類型。
變數在程式中就是用一個變數名表示了,變數名必須是大小寫英文、數字和_的組合,且不能用數字開頭,比如:
a = 1
變數a是一個整數。
t_007 = ‘T007‘
變數t_007是一個字串。
Answer = True
變數Answer是一個布爾值True。
在Python中,等號=是指派陳述式,可以把任意資料類型賦值給變數,同一個變數可以反覆賦值,而且可以是不同類型的變數,例如:
a = 123 # a是整數
print(a)
a = ‘ABC‘ # a變為字串
print(a)
加單引號雙引號的都是字串
變數在記憶體中的儲存形式:
在python中, 每一個變數在記憶體中建立,我們可以通過變數來查看記憶體中的值
在python中通過指標改變變數的值
x = 1 說明x指向了記憶體中儲存為1的地址,地址是1767137504
y = 2 說明y指向了記憶體中儲存為2的地址,地址是1767137536
也就是說在執行x = 4,y = 5之後,x,y分別指向了不同的地址
當執行 x = y之後
x指向了y所指向的記憶體了,它們都指向同一塊記憶體,跟c裡面的指標一樣
linux 下
(好像linux(64bit ubuntu)和windows(64bit windows10)佔用的記憶體大小不一樣)
在python中,一開始初始化儲存在記憶體的東西是不可以改變的,我們所能改變的只是它的指向。
為
可以看出x和1的地址是一個地址,y的地址和2是一個地址。
所以
執行 x = 1,解譯器建立了整數和變數x,並把x指向1所在的記憶體位址:
執行x = y,解譯器建立了變數y,並把y指向x指向a的記憶體位址
如果將x重新賦值abc x=‘abc‘,那麼解譯器建立了字串‘abc‘,並把x的指向改為‘abc‘所在的記憶體位址,但y並沒有更改
對變數賦值x = y是把變數x指向真正的對象,該對象是變數y所指向的。對變數y的賦值不影響變數x的指向。他們是獨立的根據不同的操作指向不同的地址。
Python支援多種資料類型,在電腦內部,可以把任何資料都看成一個“對象”,而變數就是在程式中用來指向這些資料對象的,對變數賦值就是把資料和變數關聯起來。
常量
所謂常量就是不能變的變數,比如常用的數學常數π就是一個常量。在Python中,通常用全部大寫的變數名表示常量:
PI = 3.14159265359
但事實上PI仍然是一個變數,Python根本沒有任何機制保證PI不會被改變,所以,用全部大寫的變數名表示常量只是一個習慣上的用法.
最後解釋一下整數的除法為什麼也是精確的。在Python中,有兩種除法,一種除法是/:
>> 10 / 33.3333333333333335
/除法計算結果是浮點數,即使是兩個整數恰好整除,結果也是浮點數:
>> 9 / 33.0
還有一種除法是//,稱為地板除,兩個整數的除法仍然是整數:
>> 10 // 33
整數的地板除//永遠是整數,即使除不盡。要做精確的除法,使用/就可以。
因為//除法只取結果的整數部分,所以Python還提供一個餘數運算,可以得到兩個整數相除的餘數:
>> 10 % 31
無論整數做//除法還是取餘數,結果永遠是整數,所以,整數運算結果永遠是精確的。
注意:Python的整數沒有大小限制,而某些語言的整數根據其儲存長度是有大小限制的,例如Java對32位整數的範圍限制在-2147483648-2147483647。
Python的浮點數也沒有大小限制,但是超出一定範圍就直接表示為inf(無限大)。
list
Python內建的一種資料類型是列表:list。list是一種有序的集合,可以隨時添加和刪除其中的元素。
例如:
M就是一個list
用len()函數可以獲得list元素的個數:
len(M)
用索引來訪問list中每一個位置的元素,記得索引是從0開始的:
M[0]
M[1]
當索引超出了範圍時,Python會報一個IndexError錯誤,所以,要確保索引不要越界,記得最後一個元素的索引是len(M) - 1。
如果要取最後一個元素,除了計算索引位置外,還可以用-1做索引,直接擷取最後一個元素:
M[-1]
擷取倒數第2個、倒數第3個:
M[-2]
M[-3]
list是一個可變的有序表,可以往list中追加元素到末尾:
M.append(‘d‘)
也可以把元素插入到指定的位置,比如索引號為1的位置:
M.insert(1, ‘e‘)
如果該位置有資料,那麼將當前資料插入該位置其他資料往後移動
要刪除指定位置的元素,用pop(i)方法,其中i是索引位置:
例如:
M.pop(1)
要把某個元素替換成別的元素,可以直接賦值給對應的索引位置:
M[1]=‘B‘
list裡面的元素的資料類型也可以不同,比如:
L = [‘A‘, 123, True]
list元素也可以是另一個list,比如:
s = [‘python‘, ‘java‘, [‘asp‘, ‘php‘,‘go‘], ‘C++‘,‘C‘]
還可以拆開寫
m=[‘asp‘, ‘php‘,‘go‘]
s=[‘python‘, ‘java‘, m, ‘C++‘,‘C‘]
擷取java
s[1]
擷取php
s可以看成是一個二維數組
如果一個list中一個元素也沒有,就是一個空的list,它的長度為0:
tuple
另一種有序列表叫元組:tuple。tuple和list非常類似,但是tuple一旦初始化就不能修改
A=(‘a‘,‘b‘,‘c‘)
現在,A這個tuple不能變了,它也沒有append(),insert()這樣的方法。擷取元素的方法和list是一樣的,使用A[0],A[-1],但不能賦值成另外的元素。
當A為一個tuple時,使用append方法追加資料會報錯
不可變的tuple有什麼意義?因為tuple不可變,所以代碼更安全。如果可能,能用tuple代替list就盡量用tuple。
當定義一個tuple時,在定義的時候,tuple的元素就必須被確定下來,比如:
定義一個只有1個元素的tuple,如果這麼定義:
定義的不是tuple,是1這個數!這是因為括弧()既可以表示tuple,又可以表示數學公式中的小括弧,這就產生了歧義,因此,Python規定,這種情況下,按小括弧進行計算,計算結果自然是1。
所以,只有1個元素的tuple定義時必須加一個逗號,,來消除歧義:
tuple不可變但是如果儲存的資料有列表list是可變的
其實tuple不變變化的只能是 list裡面的內容
tuple中指向的資料一直是不可變的,指向的list地址也不變,list中的內容可以變化,list也是一個地址,地址中的內容可以變化
表面上看,tuple的元素確實變了,但其實變的不是tuple的元素,而是list的元素。tuple一開始指向的list並沒有改成別的list,所以,tuple所謂的“不變”是說,tuple的每個元素,指向永遠不變。即指向‘a‘,就不能改成指向‘b‘,指向一個list,就不能改成指向其他對象,但指向的這個list本身是可變的!所有tuple的不變應該是tuple每一個元素本身不能變。
如果tuple存一個變數,只要賦給tuple那麼變數改變了tuple中的元素也不變
dict
Python內建了字典:dict的支援,dict全稱dictionary,在其他語言中也稱為map,使用鍵-值(key-value)儲存,具有極快的尋找速度。
dict根據索引值對來擷取資料,儲存的也是索引值對
儲存:d = {‘xiaoming‘: 95, ‘xiaohong‘: 90, ‘xiaowang‘: 85}
擷取:d[‘xiaoming‘]
為什麼dict尋找速度這麼快?因為dict的實現原理和查字典是一樣的。假設字典包含了1萬個漢字,我們要查某一個字,一個辦法是把字典從第一頁往後翻,直到找到我們想要的字為止,這種方法就是在list中尋找元素的方法,list越大,尋找越慢。
第二種方法是先在字典的索引表裡(比如部首表)查這個字對應的頁碼,然後直接翻到該頁,找到這個字。無論找哪個字,這種尋找速度都非常快,不會隨著字典大小的增加而變慢。
dict就是第二種實現方式,給定一個名字,比如‘Michael‘,dict在內部就可以直接計算出Michael對應的存放成績的“頁碼”,也就是95這個數字存放的記憶體位址,直接取出來,所以速度非常快。這種key-value儲存方式,在放進去的時候,必鬚根據key算出value的存放位置,這樣,取的時候才能根據key直接拿到value。
字典是無序的,比如加一個資料,再取出。
由於一個key只能對應一個value,所以,多次對一個key放入value,後面的值會把前面的值衝掉:
相當於重新賦值
如果鍵不存在會報錯
要避免key不存在的錯誤,有兩種辦法:
一是通過in判斷key是否存在:
二是通過dict提供的get()方法,如果key不存在,可以返回None,或者自己指定的value:
存在
不存在
返回None的時候Python的互動環境不顯示結果。
使用自訂傳回值
刪除一個key
用pop(key)方法,對應的value也會從dict中刪除:
刪除不存在的值會報錯
dict內部存放的順序和key放入的順序是沒有關係的。
和list比較,dict有以下幾個特點:
尋找和插入的速度極快,不會隨著key的增加而變慢;
需要佔用大量的記憶體,記憶體浪費多。
而list相反:
尋找和插入的時間隨著元素的增加而增加;
佔用空間小,浪費記憶體很少。
所以,dict是用空間來換取時間的一種方法。
dict可以用在需要高速尋找的很多地方,在Python代碼中幾乎無處不在,正確使用dict非常重要,需要牢記的第一條就是dict的key必須是不可變對象。
這是因為dict根據key來計算value的儲存位置,如果每次計算相同的key得出的結果不同,那dict內部就完全混亂了。這個通過key計算位置的演算法稱為雜湊演算法(Hash)。
要保證hash的正確性,作為key的對象就不能變。在Python中,字串、整數等都是不可變的,因此,可以放心地作為key。而list是可變的,就不能作為key:
#dict索引值對互換
mydict={"a":1,"b":2,"c":3}
mydict_new={}
for key,val in mydict.items():
mydict_new[val]=key
print(mydict_new)
mydict={"a":‘A‘,"b":‘B‘,"c":‘C‘}
mydict_new=dict([val,key] for key,val in mydict.items())
mydict={"a":‘A‘,"b":‘B‘,"c":‘C‘}
mydict_new=dict(zip(mydict.values(),mydict.keys()))
print(mydict_new)
set
set和dict類似,也是一組key的集合,但不儲存value。由於key不能重複,所以,在set中,沒有重複的key。
要建立一個set,需要提供一個list作為輸入集合:
傳入的參數[1, 2, 3]是一個list,而顯示的{1, 2, 3}只是告訴你這個set內部有1,2,3這3個元素,顯示的順序也不表示set是有序的。。
重複元素在set中自動被過濾:
通過add(key)方法可以添加元素到set中,可以重複添加,但不會有效果:
通過remove(key)方法可以刪除元素:
set可以看成數學意義上的無序和無重複元素的集合,因此,兩個set可以做數學意義上的交集、並集等操作:
交集
並集
set和dict的唯一區別僅在於沒有儲存對應的value,但是,set的原理和dict一樣,所以,同樣不可以放入可變對象,因為無法判斷兩個可變對象是否相等,也就無法保證set內部“不會有重複元素”。
把list放入set,會報錯。
切片
取一個list或tuple的部分元素是非常常見的操作。
定義一個list
L=[1,2,3,4,5,‘a‘,‘b‘,‘c‘,‘d‘]
取前三個
可以使用
第一個辦法
L=[1,2,3,4,5,‘a‘,‘b‘,‘c‘,‘d‘]
print(L[0])
print(L[1])
print(L[2])
第二個辦法
也可以使用迴圈
L=[1,2,3,4,5,‘a‘,‘b‘,‘c‘,‘d‘]
m=[]
n=6
for i in range(n):
m.append(L[i])
print(m)
第三個辦法
使用第一種辦法效率太差,第二種迴圈比較繁瑣
python提供了切片操作可以大大簡化這種繁瑣的操作
L=[1,2,3,4,5,‘a‘,‘b‘,‘c‘,‘d‘]
d=L[0:6]
print(d)
L[0:6]表示,從索引0開始取,直到索引6為止,但不包括索引6。即索引1, 2, 3, 4, 5, ‘a‘正好是6個元素(a的索引為5即6-1,第一個參數是從哪個索引開始,第二個是到N-1的索引結束或者理解為取第二個參數減去第一個參數的個數)切片可以大大簡化繁瑣的操作。
切片可以從前面取資料也可以從後面取資料
迭代(iteration)
迭代:iteration
可迭代的:Iterable
迭代器:iterator
迭代相比較迭代器更加抽象,這就好比,遍曆一個字典dict,用到for...in...的操作,稱之為在 迭代,而這種能遍曆的行為或者能迭代的行為稱之為可迭代的,而迭代器是具體到迭代行為的操作者或者說是實行者,在Python中有個函數專門返回的就是迭代器對象,而這個對象可以通過next的屬性對dict同樣進行遍曆,我們又稱這種現象為迭代器
在python中一個list或tuple,要想訪問其中的某個元素,可以通過下標來訪問,如果想要訪問所有的元素,那可以用for迴圈來遍曆這個list或者tuple,而這種遍曆就叫做迭代。
在Python中,迭代通過for..in..來完成。
python的for迴圈不僅可以用在 list和tuple上,還可以作用在其他可迭代的對象上
例如:
d = {‘name‘: ‘Jack‘, ‘age‘: 18, ‘job‘: ‘Coder‘}
print(d) # 首先輸出dict
print("迭代key")
for s in d:
print(s)
print("迭代value")
for value in d.values():
print(value)
print(‘迭代key和value‘)
for k, v in d.items():
print(‘key:%s,value:%s‘ % (k, v))
輸出結果
字串也可以進行迭代,迭代出每個字元:
for i in ‘Hello World‘:
print(i,end="")
輸出結果
可迭代的(Iterable)
如果一個list、tuple或者一個字串可以遍曆,也就是有迭代的行為,稱為是可以迭代的
結果
int型的數字不可迭代
字串,list,tuple,dict,set等可以迭代
Python內建的enumerate函數可以把一個list變成 索引-元素對,這樣就可以在for迴圈中同時迭代索引(下標)和元素(key)本身
輸出結果:
print("list變成 索引-元素對")
for index,value in enumerate([‘first‘,‘second‘,‘third‘]):
print(index,":",value)
print("dict變成 索引-元素對")
for index,key in enumerate({‘first‘:1,‘second‘:2,‘third‘:3}):
print(index,":",key)
迭代的對象實際上是一個list,這個list的每一個元素又是一個tuple,且每個tuple對象有N個元素,這樣的話,就不能單單通過 for x in list:的方式來取了,應該可以這樣寫,for N1,N2,N3...in list:(要保證tuple的個數相等)
結果
如果不相等會報錯
結果
迭代器(Iterator)
可以被next()函數調用並不斷返回下一個值的對象稱為迭代器:Iterator。
可以直接作用於for迴圈的資料類型有以下幾種:
一類是集合資料類型,如list、tuple、dict、set、str等;
一類是generator,包括產生器和帶yield的generator function。
這些可以直接作用於for迴圈的對象統稱為可迭代對象:Iterable
產生器都是Iterator對象,但list、dict、str雖然是Iterable,卻不是Iterator。
可以使用isinstance()判斷一個對象是否是Iterator對象
from collections import Iterator
isinstance((x for x in range(10)), Iterator)
isinstance([], Iterator)
isinstance({}, Iterator)
isinstance(‘abc‘, Iterator)
把list、dict、str等Iterable變成Iterator可以使用iter()函數
定義一個list,並通過iter獲得list的迭代器對象
L = [‘python2‘,‘iter‘,26,‘Python3‘]
it = iter(L) #獲得list的迭代器對象
print(it)
while True:
x = next(it)
print(x)
輸出結果報錯
這是因為next()不知道什麼時候停止
將代碼修改下:
L = [‘python2‘,‘iter‘,26,‘Python3‘]
it = iter(L) #獲得list的迭代器對象
while True:
try:#try捕獲異常
x=next(it)
print(x)
except StopIteration:#當捕獲到迭代行為終止的時候,也就是無元素可以next的時候,終止迴圈
break
輸出結果正常
為什麼list、dict、str等資料類型不是Iterator?
因為Python的Iterator對象表示的是一個資料流,Iterator對象可以被next()函數調用並不斷返回下一個資料,直到沒有資料時拋出StopIteration錯誤。可以把這個資料流看做是一個有序序列,但我們卻不能提前知道序列的長度,只能不斷通過next()函數實現按需計算下一個資料,所以Iterator的計算是惰性的,只有在需要返回下一個資料時它才會計算。
Iterator甚至可以表示一個無限大的資料流,例如全體自然數。而使用list是永遠不可能儲存全體自然數的。
小結
凡是可作用於for迴圈的對象都是Iterable類型;
凡是可作用於next()函數的對象都是Iterator類型,它們表示一個惰性計算的序列;
集合資料類型如list、dict、str等是Iterable但不是Iterator,不過可以通過iter()函數獲得一個Iterator對象。
Python的for迴圈本質上就是通過不斷調用next()函數實現的,例如:
# for x in [1, 2, 3, 4, 5]:
print(x)
等價於
# 首先獲得Iterator對象:
it = iter([1, 2, 3, 4, 5])
# 迴圈:while True:
try:
# 獲得下一個值:
x = next(it)
except StopIteration:
# 遇到StopIteration就退出迴圈
break
python基礎--資料類型