目錄| [上一節 (2.3 格式化)]() | 下一節 (2.5 Collections模塊)python
Python 有三種序列數據類型。git
'Hello'
。字符串是字符序列[1, 4, 5]
。('GOOG', 100, 490.1)
。全部的序列都是有序的,由整數進行索引,而且具備長度。github
a = 'Hello' # String b = [1, 4, 5] # List c = ('GOOG', 100, 490.1) # Tuple # Indexed order a[0] # 'H' b[-1] # 5 c[1] # 100 # Length of sequence len(a) # 5 len(b) # 3 len(c) # 3
序列能夠經過重複操做符 * 進行重複:s * n
。segmentfault
>>> a = 'Hello' >>> a * 3 'HelloHelloHello' >>> b = [1, 2, 3] >>> b * 2 [1, 2, 3, 1, 2, 3] >>>
相同類型的序列能夠經過加號 + 進行拼接:s + t
。函數
>>> a = (1, 2, 3) >>> b = (4, 5) >>> a + b (1, 2, 3, 4, 5) >>> >>> c = [1, 5] >>> a + c Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: can only concatenate tuple (not "list") to tuple
切片是指着從序列中提取子序列。切片的語法爲 s[start:end]
。 start
和 end
是想要的子序列的索引。oop
a = [0,1,2,3,4,5,6,7,8] a[2:5] # [2,3,4] a[-5:] # [4,5,6,7,8] a[:3] # [0,1,2]
start
和 end
必須是整數。在列表上,切片能夠被從新賦值和刪除。編碼
# Reassignment a = [0,1,2,3,4,5,6,7,8] a[2:4] = [10,11,12] # [0,1,10,11,12,4,5,6,7,8]
注意:從新賦值的切片不須要具備相同的長度。翻譯
# Deletion a = [0,1,2,3,4,5,6,7,8] del a[2:4] # [0,1,4,5,6,7,8]
有一常見的函數用於把序列縮減爲單個值。code
>>> s = [1, 2, 3, 4] >>> sum(s) 10 >>> min(s) 1 >>> max(s) 4 >>> t = ['Hello', 'World'] >>> max(t) 'World' >>>
可使用 for 循環對序列中的元素進行迭代。索引
>>> s = [1, 4, 9, 16] >>> for i in s: ... print(i) ... 1 4 9 16 >>>
在循環的每次迭代中,會獲取一個新的項來處理。這個新的值會被放到迭代變量中。在此示例中,迭代變量爲 x:
for x in s: # `x` is an iteration variable ...statements
在每次迭代中,迭代變量的先前值會被覆蓋(若是有)。循環結束後,迭代變量保留最後一個值。
可使用 break
語句提早跳出循環。
for name in namelist: if name == 'Jake': break ... ... statements
當 break
語句執行時,它退出循環而且進入下一個語句。break
語句僅應用於最內部的循環。若是此循環在另外一個循環的內部,那麼 break
不會中斷外部循環。
要跳過一個元素而且進入到下一個,請使用 continue
語句。
for line in lines: if line == '\n': # Skip blank lines continue # More statements ...
若是當前項不重要或者是在處理時須要忽略,那麼使用 continue
語句頗有用。
若是須要計數,請使用 range()
函數。
for i in range(100): # i = 0,1,...,99
range() 函數的語法是range([start,] end [,step])
。
for i in range(100): # i = 0,1,...,99 for j in range(10,20): # j = 10,11,..., 19 for k in range(10,50,2): # k = 10,12,...,48 # Notice how it counts in steps of 2, not 1.
start
是可選的 , 默認值是 0
。step
是可選的,默認值是 1
。range()
才計算值,實際上,它不存儲大範圍的數。enumerate
函數爲迭代添加一個額外的計數值。
names = ['Elwood', 'Jake', 'Curtis'] for i, name in enumerate(names): # Loops with i = 0, name = 'Elwood' # i = 1, name = 'Jake' # i = 2, name = 'Curtis'
通常格式爲enumerate(sequence [, start = 0])
,start
是可選的,一個很好的使用示例:讀取文件時跟蹤行數。
with open(filename) as f: for lineno, line in enumerate(f, start=1): ...
enumerate
能夠當作如下語句的簡寫:
i = 0 for x in s: statements i += 1
使用 enumerate
函數能夠減小輸入,運行速度也稍快一些。
能夠迭代多個變量:
points = [ (1, 4),(10, 40),(23, 14),(5, 6),(7, 8) ] for x, y in points: # Loops with x = 1, y = 4 # x = 10, y = 40 # x = 23, y = 14 # ...
當使用多個變量時,每一個元組被拆包爲一組迭代變量。變量的數目必須與每一個元組中的項數匹配。
zip
函數採用多個序列,而且生成將它們組合在一塊兒的迭代器。
columns = ['name', 'shares', 'price'] values = ['GOOG', 100, 490.1 ] pairs = zip(columns, values) # ('name','GOOG'), ('shares',100), ('price',490.1)
要得到結果,必須進行迭代。能夠如先前所示的那樣使用多個變量對元組進行拆包。
for column, value in pairs: ...
zip
函數的常見用法是建立用於構造字典的鍵值對。
d = dict(zip(columns, values))
嘗試一些基本的計數示例:
>>> for n in range(10): # Count 0 ... 9 print(n, end=' ') 0 1 2 3 4 5 6 7 8 9 >>> for n in range(10,0,-1): # Count 10 ... 1 print(n, end=' ') 10 9 8 7 6 5 4 3 2 1 >>> for n in range(0,10,2): # Count 0, 2, ... 8 print(n, end=' ') 0 2 4 6 8 >>>
交互地試驗一些序列縮減操做。
>>> data = [4, 9, 1, 25, 16, 100, 49] >>> min(data) 1 >>> max(data) 100 >>> sum(data) 204 >>>
嘗試遍歷數據。
>>> for x in data: print(x) 4 9 ... >>> for n, x in enumerate(data): print(n, x) 0 4 1 9 2 1 ... >>>
有時候,for
語句,len()
和 range()
函數被初學者用於一些可怕的代碼片斷中,這些代碼看起來像來自於古老的 C 程序。
>>> for n in range(len(data)): print(data[n]) 4 9 1 ... >>>
不要那樣作。閱讀這些代碼不只辣眼睛,並且內存效率低,運行慢。若是想要迭代數據,使用普通的for
循環便可。若是碰巧由於某些緣由須要使用索引,請使用 enumerate()
函數。
回想一下,Data/missing.csv
文件包含一個股票投資組合的數據,可是有一些行缺乏值。請使用 enumerate()
函數修改 pcost.py
程序,以便在遇到錯誤的輸入時,打印帶有警告信息的行號。
>>> cost = portfolio_cost('Data/missing.csv') Row 4: Couldn't convert: ['MSFT', '', '51.23'] Row 7: Couldn't convert: ['IBM', '', '70.44'] >>>
爲此,須要修改部分代碼。
... for rowno, row in enumerate(rows, start=1): try: ... except ValueError: print(f'Row {rowno}: Bad row: {row}')
在 Data/portfolio.csv
文件中,第一行包含列標題。在以前全部代碼中,咱們把它丟棄了。
>>> f = open('Data/portfolio.csv') >>> rows = csv.reader(f) >>> headers = next(rows) >>> headers ['name', 'shares', 'price'] >>>
可是,若是標題要用於其它有用的事情呢?這就涉及到 zip()
函數了。首先,嘗試把文件標題和數據行配對。
>>> row = next(rows) >>> row ['AA', '100', '32.20'] >>> list(zip(headers, row)) [ ('name', 'AA'), ('shares', '100'), ('price', '32.20') ] >>>
請注意 zip()
函數是如何把列標題與列值配對。在這裏,咱們使用 list()
函數把結果轉換爲列表,以便查看。一般,zip()
函數建立一個必須由 for 循環使用的迭代器。
這種配對是構建字典的中間步驟。如今嘗試:
>>> record = dict(zip(headers, row)) >>> record {'price': '32.20', 'name': 'AA', 'shares': '100'} >>>
在處理大量數據文件時,這種轉換是最有用的技巧之一。例如,假設須要使 pcost.py
程序處理各類輸入文件,可是不考慮名稱,份額,價格所在列的編號。
修改 pcost.py
程序中的 portfolio_cost()
,使其看起來像這樣:
# pcost.py def portfolio_cost(filename): ... for rowno, row in enumerate(rows, start=1): record = dict(zip(headers, row)) try: nshares = int(record['shares']) price = float(record['price']) total_cost += nshares * price # This catches errors in int() and float() conversions above except ValueError: print(f'Row {rowno}: Bad row: {row}') ...
如今,在一個徹底不一樣的數據文件 Data/portfoliodate.csv
(以下所示)上嘗試 portfolio_cost() 函數。
name,date,time,shares,price "AA","6/11/2007","9:50am",100,32.20 "IBM","5/13/2007","4:20pm",50,91.10 "CAT","9/23/2006","1:30pm",150,83.44 "MSFT","5/17/2007","10:30am",200,51.23 "GE","2/1/2006","10:45am",95,40.37 "MSFT","10/31/2006","12:05pm",50,65.10 "IBM","7/9/2006","3:15pm",100,70.44
>>> portfolio_cost('Data/portfoliodate.csv') 44671.15 >>>
若是操做正確,會發現程序仍然可以正常運行,即便數據文件的列格式與以前的徹底不一樣,這很酷!
此處所作的更改是微妙的,可是卻意義重大。新版的 portfolio_cost()
能夠讀取任何 CSV 文件,並從中選擇須要的值,而不是硬編碼去讀取單個固定文件格式。只要文件有必要的列,代碼就能正常運行。
修改在 2.3 節編寫的 report.py
程序,以便可以使用相同的技術挑選出列標題。
嘗試以 Data/portfoliodate.csv
文件做爲輸入,運行 report.py
程序,並觀察是否生成和以前同樣的答案。
字典將鍵映射到值。例如,股票價格字典。
>>> prices = { 'GOOG' : 490.1, 'AA' : 23.45, 'IBM' : 91.1, 'MSFT' : 34.23 } >>>
若是使用字典的 items()
方法,那麼能夠獲取到鍵值對 (key,value)
:
>>> prices.items() dict_items([('GOOG', 490.1), ('AA', 23.45), ('IBM', 91.1), ('MSFT', 34.23)]) >>>
可是,若是想要獲取 (value, key)
鍵值對列表呢?
提示:使用 zip()
函數。
>>> pricelist = list(zip(prices.values(),prices.keys())) >>> pricelist [(490.1, 'GOOG'), (23.45, 'AA'), (91.1, 'IBM'), (34.23, 'MSFT')] >>>
爲何這樣操做?首先,這容許對字典數據執行確切類型的數據處理。
>>> min(pricelist) (23.45, 'AA') >>> max(pricelist) (490.1, 'GOOG') >>> sorted(pricelist) [(23.45, 'AA'), (34.23, 'MSFT'), (91.1, 'IBM'), (490.1, 'GOOG')] >>>
其次,這也說明了元組的一個重要特徵,當在比較中使用元組時,從第一項開始,逐元素進行比較,相似於字符串中字符與字符逐個比較。
zip()
函數常常應用於須要從不一樣的地方把數據進行配對。例如,爲了使用已命名的值構建字典,將列名和列值進行配對。
請注意,zip()
函數不限於一對。例如,可使用任意數量的列表做爲輸入。
>>> a = [1, 2, 3, 4] >>> b = ['w', 'x', 'y', 'z'] >>> c = [0.2, 0.4, 0.6, 0.8] >>> list(zip(a, b, c)) [(1, 'w', 0.2), (2, 'x', 0.4), (3, 'y', 0.6), (4, 'z', 0.8))] >>>
另外,請注意,一旦最短的輸入序列耗盡,zip()
函數將會中止。
>>> a = [1, 2, 3, 4, 5, 6] >>> b = ['x', 'y', 'z'] >>> list(zip(a,b)) [(1, 'x'), (2, 'y'), (3, 'z')] >>>
目錄| [上一節 (2.3 格式化)]() | 下一節 (2.5 Collections模塊)