目錄 | 上一節 (2.1 數據類型) | 下一節 (2.3 格式化)python
本節討論列表(list),字典(dict)和集合(set)。git
一般,程序必須處理許多對象。github
這裏有三種主要的選擇(譯註:數據結構)可使用:shell
當數據順序很重要時,請使用列表。記住,列表能夠存儲任何類型的對象。例如,包含元組的列表:segmentfault
portfolio = [ ('GOOG', 100, 490.1), ('IBM', 50, 91.3), ('CAT', 150, 83.44) ] portfolio[0] # ('GOOG', 100, 490.1) portfolio[2] # ('CAT', 150, 83.44)
從零開始構建列表。數組
records = [] # Initial empty list # Use .append() to add more items records.append(('GOOG', 100, 490.10)) records.append(('IBM', 50, 91.3)) ...
從文件讀取記錄的示例:數據結構
records = [] # Initial empty list with open('Data/portfolio.csv', 'rt') as f: next(f) # Skip header for line in f: row = line.split(',') records.append((row[0], int(row[1]), float(row[2])))
若是要快速隨機查找(經過鍵名),那麼字典頗有用。例如,股票價格字典:app
prices = { 'GOOG': 513.25, 'CAT': 87.22, 'IBM': 93.37, 'MSFT': 44.12 }
如下是一些簡單的查找:函數
>>> prices['IBM'] 93.37 >>> prices['GOOG'] 513.25 >>>
從零開始構建字典的示例:測試
prices = {} # Initial empty dict # Insert new items prices['GOOG'] = 513.25 prices['CAT'] = 87.22 prices['IBM'] = 93.37
從文件內容填充字典的示例:
prices = {} # Initial empty dict with open('Data/prices.csv', 'rt') as f: for line in f: row = line.split(',') prices[row[0]] = float(row[1])
注意:若是是在 Data/prices.csv
文件上嘗試此操做,會發現幾乎能夠正常工做——可是,在末尾有一個空行致使程序崩潰了。須要找出一些方法來修改代碼以解決此問題(參見練習 2.6)。
測試鍵是否存在:
if key in d: # YES else: # NO
能夠查找可能不存在的值,並在值不存在的狀況下提供默認值。
name = d.get(key, default)
示例:
>>> prices.get('IBM', 0.0) 93.37 >>> prices.get('SCOX', 0.0) 0.0 >>>
在 Python 中,幾乎任何類型的值均可以用做字典的鍵。字典的鍵必須是不可變類型。例如,元組:
holidays = { (1, 1) : 'New Years', (3, 14) : 'Pi day', (9, 13) : "Programmer's day", }
而後訪問:
>>> holidays[3, 14] 'Pi day' >>>
列表,集合或者其它字典都不能用做字典的鍵,由於列表和字典(譯註:集合也是使用哈希技術實現的)是可變的。
集合是互異且無序的數據。
tech_stocks = { 'IBM','AAPL','MSFT' } # Alternative syntax tech_stocks = set(['IBM', 'AAPL', 'MSFT'])
集合對於成員關係測試頗有用。
>>> tech_stocks set(['AAPL', 'IBM', 'MSFT']) >>> 'IBM' in tech_stocks True >>> 'FB' in tech_stocks False >>>
集合對於消除重複也頗有用。
names = ['IBM', 'AAPL', 'GOOG', 'IBM', 'GOOG', 'YHOO'] unique = set(names) # unique = set(['IBM', 'AAPL','GOOG','YHOO'])
其它集合操做:
names.add('CAT') # Add an item names.remove('YHOO') # Remove an item s1 | s2 # Set union s1 & s2 # Set intersection s1 - s2 # Set difference
在這些練習中,你開始構建的程序是本課程剩餘部分使用的主要程序之一。請在 Work/report.py
文件中工做。
Data/portfolio.csv
文件包含投資組合中的股票列表。在 練習 1.30 中,你編寫了一個讀取該文件並執行簡單計算的 portfolio_cost(filename)
函數。
代碼看起來應該像下面這樣:
# pcost.py import csv def portfolio_cost(filename): '''Computes the total cost (shares*price) of a portfolio file''' total_cost = 0.0 with open(filename, 'rt') as f: rows = csv.reader(f) headers = next(rows) for row in rows: nshares = int(row[1]) price = float(row[2]) total_cost += nshares * price return total_cost
請使用這些代碼做爲指導,建立一個新文件 report.py
。在 report.py
文件中,定義 read_portfolio(filename)
函數,該函數打開 Data/portfolio.csv
文件並將其讀入到包含元組的列表中。爲此,你須要對上面的代碼作一些小修改。
首先,建立一個最初設爲空列表的變量,而不是定義 total_cost = 0
。例如:
portfolio = []
接着,把每一行準確地存儲到元組中(就像在上次的練習中作的那樣),而後把元組追加到列表中,而不是合計總的費用。
for row in rows: holding = (row[0], int(row[1]), float(row[2])) portfolio.append(holding)
最後,返回獲得的portfolio
列表。
請交互式地試驗函數(提醒,要執行此操做,首先須要在解釋器運行 report.py
程序)。
提示:當在終端執行文件的時候,請使用 -i
參數。
>>> portfolio = read_portfolio('Data/portfolio.csv') >>> portfolio [('AA', 100, 32.2), ('IBM', 50, 91.1), ('CAT', 150, 83.44), ('MSFT', 200, 51.23), ('GE', 95, 40.37), ('MSFT', 50, 65.1), ('IBM', 100, 70.44)] >>> >>> portfolio[0] ('AA', 100, 32.2) >>> portfolio[1] ('IBM', 50, 91.1) >>> portfolio[1][1] 50 >>> total = 0.0 >>> for s in portfolio: total += s[1] * s[2] >>> print(total) 44671.15 >>>
建立的包含元組的列表很是相似於二維(2-D)數組。例如,使用諸如 portfolio[row][column]
( row
和column
是整數)的查找來訪問特定的列和行。
也就是說,可使用像下面這樣的語句重寫最後的 for 循環:
>>> total = 0.0 >>> for name, shares, price in portfolio: total += shares*price >>> print(total) 44671.15 >>>
使用字典(而不是元組)修改在練習 2.4 中編寫的函數來表示投資組合中的股票。在字典中,使用字段名 "name", "shares" 和 "price" 來表示輸入文件中的不一樣列。
以與練習 2.4 中相同的方式試驗這個新的函數。
>>> portfolio = read_portfolio('Data/portfolio.csv') >>> portfolio [{'name': 'AA', 'shares': 100, 'price': 32.2}, {'name': 'IBM', 'shares': 50, 'price': 91.1}, {'name': 'CAT', 'shares': 150, 'price': 83.44}, {'name': 'MSFT', 'shares': 200, 'price': 51.23}, {'name': 'GE', 'shares': 95, 'price': 40.37}, {'name': 'MSFT', 'shares': 50, 'price': 65.1}, {'name': 'IBM', 'shares': 100, 'price': 70.44}] >>> portfolio[0] {'name': 'AA', 'shares': 100, 'price': 32.2} >>> portfolio[1] {'name': 'IBM', 'shares': 50, 'price': 91.1} >>> portfolio[1]['shares'] 50 >>> total = 0.0 >>> for s in portfolio: total += s['shares']*s['price'] >>> print(total) 44671.15 >>>
在這裏能夠看到,每一個條目的不一樣字段是經過鍵名來訪問的,而不是數字類型的列號。這一般是首選方式,由於這樣獲得的代碼在之後易於閱讀。
查看大型的字典或者列表可能會很混亂。要使調試的輸出變得整潔,能夠考慮使用 pprint()
函數。
>>> from pprint import pprint >>> pprint(portfolio) [{'name': 'AA', 'price': 32.2, 'shares': 100}, {'name': 'IBM', 'price': 91.1, 'shares': 50}, {'name': 'CAT', 'price': 83.44, 'shares': 150}, {'name': 'MSFT', 'price': 51.23, 'shares': 200}, {'name': 'GE', 'price': 40.37, 'shares': 95}, {'name': 'MSFT', 'price': 65.1, 'shares': 50}, {'name': 'IBM', 'price': 70.44, 'shares': 100}] >>>
在使用索引而不是數字查找某元素的地方,字典是一種用來跟蹤元素的頗有用的方式。在 Python shell 中,嘗試使用字典:
>>> prices = { } >>> prices['IBM'] = 92.45 >>> prices['MSFT'] = 45.12 >>> prices ... look at the result ... >>> prices['IBM'] 92.45 >>> prices['AAPL'] ... look at the result ... >>> 'AAPL' in prices False >>>
該 Data/prices.csv
文件包含一系列帶有股票價格的行,看起來像下面這樣:
"AA",9.22 "AXP",24.85 "BA",44.85 "BAC",11.27 "C",3.72 ...
編寫 read_prices(filename)
函數將諸如此類的價格集合讀取到字典中,字典的鍵表明股票的名字,字典的值表明股票的價格。
爲此,從空字典開始,而且像上面作的那樣開始插入值。可是,如今正在從從文件中讀取值。
咱們將使用該數據結構快速查找給定名稱的股票的價格。
這部分須要一些小技巧。首先,確保像以前作的那樣使用 csv
模塊——無需在這裏重複發明輪子。
>>> import csv >>> f = open('Data/prices.csv', 'r') >>> rows = csv.reader(f) >>> for row in rows: print(row) ['AA', '9.22'] ['AXP', '24.85'] ... [] >>>
另一個小麻煩是 Data/prices.csv
文件可能有一些空行在裏面。注意上面數據的最後一行是一個空列表——意味在那一行沒有數據。
這有可能致使你的程序由於異常而終止。酌情使用 try
和 except
語句捕獲這些異常。思考:使用 if
語句來防範錯誤的數據是否會更好?
編寫完 read_prices()
函數,請交互式地測試它並確保其正常工做:
>>> prices = read_prices('Data/prices.csv') >>> prices['IBM'] 106.28 >>> prices['MSFT'] 20.89 >>>
經過添加一些計算盈虧的語句到 report.py
程序,將全部的工做聯繫到一塊兒。這些語句應該採用在練習 2.5 中存儲股票名稱的列表,以及在練習 2.6 中存儲股票價格的字典,並計算投資組合的當前值以及盈虧。