《Python核心編程》筆記(二)


今次的內容主要為字典、集合、迭代器、列表解析、生成器表達式和檢測與處理異常這幾部分內容,中間抑或摻加一些文件方面的內容。

注:本書為第二版,其中python的代碼主要為2.x版本,使用python3.x的朋友請留意。

字典

另類創建字典之方法

代碼示例:

1
2
3
4
5
6
fdict = dict((['x',1],['y',2]))
#fdict => {'y':2, 'x':1}
ddict = {}.fromkeys(('x','y'),-1)
#ddict => {'y':-1, 'x':-1}
edict = {}.fromkeys(('foo','bar'))
#edict => {'foo':None, 'bar':None}

另類字典遍歷之方法

代碼示例:

1
2
3
4
dict2['name'] = 'venus'
dict2['port'] = 80
print('host %(name)s is running on port %(port)d' % dict2)
#輸出:host venus is running on port 80

刪除字典元素和字典

代碼示例:

1
2
3
4
del dict2['name']  #刪除鍵為'name'的條目
dict2.clear() #刪除dict2中所有的條目
del dict2 #刪除整個dict2字典
dict2.pop('name') #刪除並返回鍵為'name'的條目

字典比較之方法

簡單來說字典的比較算法會按照如下的順序進行:

  1. 比較字典長度,長者為大
  2. 比較字典的鍵,鍵比較的順序與keys()方法返回鍵的順序相同
  3. 比較字典中相同鍵的值

下面這個原理圖解釋了這一算法:

字典的工廠函數dict()

代碼示例:

1
2
3
4
5
6
>>> dict(zip(('x', 'y'),(1, 2)))
{'y':2, 'x':1}
>>> dict([['x', 1],['y', 2]])
{'y':2, 'x':1}
>>> dict([('xy'[i-1], i)for i in range(1, 3)])
{'y':2, 'x':1}

如果輸入的參數是另一個映射對象,比如一個字典對象,對其調用dict()會從存在的字典裡複製內容來生成新的字典。新生成的字典是原來字典對象的淺複製版本,它與用字典的內建方法copy()生成的字典對象是一樣的,不過其速度比copy方法要慢。

代碼示例:

1
2
3
4
5
6
7
8
9
10
11
>>> dict(x=1, y=2)
{'y':2, 'x':1}
>>> dict8 = dict(x=1, y=2)
>>> dict8
{'y':2, 'x':1}
>>> dict9 = dict(**dict8) #非最好的方法
>>> dict9
{'y':2, 'x':1}
>>> dict9 = dict8.copy()
>>> dict9
{'y':2, 'x':1}

keys方法可以返回字典所有的鍵,但是是沒有順序的,如果我們希望對其進行排序,可以這麼做:

代碼示例:

1
2
3
4
>>> for eachKey in sorted(dict2):
... print('dict2 key', eachKey, 'has value', dict2[eachKey])
dict2 key name has value earth
dict2 key port has value 80

update()可以用來將一個字典的內容添加到另外一個字典中。字典中原有的鍵如果與新添加的鍵重複,那麼重複鍵所對應的原有條目的值將被新鍵所對應的值所覆蓋。

所有不可變的類型都是可哈希的,因此它們都可以作為字典的鍵。注:值相同的數字表示相同的鍵,即1和1.0的哈希值是相同的。另外,若元組中包含列表,則該元組不可作為字典的鍵。

集合

集合創建

代碼示例:

1
2
3
4
>>> s = set('cheeseshop')
>>> s
set(['c','h','e','o','p','s']) #此為可變集合
#若將上述代碼中的set換為frozenset,則為不可變集合

集合更新

s.add(‘z’), s.update(‘pypi’), s.remove(‘z’), s -= set(‘pypi’)

集合支持比較大小的運算,其含義與子集、超集之概念相同。

集合運算

  • 聯合(並集) s | t
  • 交集 s & t
  • 差集 s - t
  • 異或 s ^ t

注:若左右操作數類型不同(即一個是可變集合而另一個是不可變集合),則所產生的結果類型與左操作數的類型相同,另外,加號不是集合類型的操作符。

另外,只適合於可變集合的運算符還有:|=, &=, -=, ^=

##怎麼在python中實現switch語句

python中並沒有switch–case語句,但這並不表示我們需要寫大量的elif語句,事實上,我們可以這樣:

代碼示例:

1
2
3
4
if user.cmd in ('create', 'delete', 'update'):
action = '%s item' % user.cmd
else:
action = 'invalid choice...try again!'
1
2
3
4
5
msgs = {'create': 'create item',
'delete': 'delete item',
'update': 'update item'}
default = 'invalid choice...try again!'
action = msgs.get(user.cmd, default)

使用字典的一大好處是它的搜索操作比類似if-elif-else語句或是for循環這樣的序列查詢速度要快得多。

三元操作符

X if C else Y

代碼示例:

1
2
3
4
>>> x, y = 4, 3
>>> smaller = x if x < y else y
>>> smaller
3

迭代器

迭代器的限制:

迭代器不能向後移動,不能回到開始,不能複制一個迭代器而只能新建另一個。

代碼示例:

1
2
3
4
5
6
7
8
9
10
>>> myTuple = (123,'xyz',45.67)
>>> i = iter(myTuple)
>>> i.next()
123
>>> i.next()
'xyz'
>>> i.next()
45.67
>>> i.next()
#出錯!

注:在迭代可改變對象的時候修改它們並不是個好主意,因為一個序列的迭代器只是記錄你當前到達第幾個元素,所以如果你在迭代的時候改變了元素,更新會立刻反映到你所迭代的條目上。

列表解析

語法:

[expr for iter_var in iterable if cond_expr]
注:列表解析支持多重for循環(為嵌套關係)和多個if語句(為並列關係)

代碼示例:

1
2
[x ** 2 for x in range(6)]  #這種方式比下面的通過map方法構建的方式效率高
map(lambda x: x ** 2,range(6))

迭代矩陣(3×5):

[(x + 1, y + 1) for x in range(3) for y in range(5)]

生成器表達式

語法:(與列表解析語法非常相似)

(expr for iter_var in iterable if cond_expr)

與列表解析不同,生成器表達式並不創建列表,而是返回一個生成器。這個生成器在每次計算出一個條目之後,會把這個條目“生產”出來,這種做法節約了內存。

文件和輸入輸出

輸入輸出方法

注:當使用輸入方法如read()或readlines()時,python並不會刪除行結束符,這個操作被留給了程序員,所以如下的代碼經常會出現:

1
2
3
f = open('myFile','r')
data = [line.strip() for line in f.readlines()]
f.close()

注:write()和writelines()也不會自動添加行結束符。

truncate()接受一個可選的size作為參數,若指定則文件將被截取到最多size個字節處;若沒有傳遞,則默認截取到文件指針所指向的當前位置。例如:你打開一個文件之後立刻調用該方法,則你打開的這個文件會被刪除。

seek()接受一個叫做offset的參數,該函數可移動文件指針到不同的位置。offset若為0,則表示移動文件指針到文件開頭,為1則表示從當前位置開始算起,為2時則會移動到文件末尾。tell()可告訴你當前文件指針的位置。

sys.argv為命令行參數的列表,其長度len(sys.argv)為參數個數。

注:若要查詢os模塊對文件、目錄的操作方法,可查閱本書9.7節。

檢測和處理異常

異常可以通過try語句來檢測,try語句主要有兩種形式:try-except和try-finally。這兩個語句是互斥的,即你只能使用其中一種。一個try語句可對應多個except語句,但只能對應一個finally語句,或是一個try-except-finally複合語句。你可以使用try-except語句檢測和處理異常,你也可以添加一個可選的else語句處理沒有檢測到異常時執行的代碼,而try-finally只允許檢測異常並做一些必要的清除工作(無論發生錯誤與否),沒有任何異常處理設施。然而複合語句可以做到以上兩者。

try語句塊中異常發生點之後的剩餘語句將永遠不會被執行,一旦一個異常被引發,解釋器將搜索處理器。一旦找到,就開始執行處理器中的代碼,若沒有找到,則向上移交給調用者處理,若始終找不到,python解釋器會顯示出跟踪記錄。

我們還可以在一個except語句中處理多個異常,except語句在處理多個異常時要求異常被放到一個元組中。

1
2
except(exc1[, exc2[, ...excn]])[as reason]:
suite_for_exception_exc1_to_excn

異常參數

異常可以擁有參數,異常引發之後它會被傳遞給異常處理器,該參數是作為附加信息傳遞給處理器的,代碼示例如下:

1
except exception as e:  #e即為異常參數

e為一個包含來自導致異常的代碼的診斷信息的類實例,異常參數自身會組成一個元組,並存儲為類實例(異常類的實例)的屬性。你可以通過print函數來打印e中所包含的信息,你還可以通過str函數來獲得一個比較友好的字符串表示。

異常語句中else的含義

在else範圍中的任何語句被執行之前,try範圍中的所有代碼必須完全執行成功,即運行結束之前沒有引發任何異常。而finally範圍中的代碼則是無論異常是否發生,是否捕捉成功都會被執行。

完成的檢測與處理異常的代碼結構

1
2
3
4
5
6
7
8
try:
A
except MyException: #可有多個
B
else: #可選
C
finally: #可選
D

注:無異常時執行ACD,有異常時執行ABD。

try-finally

try與finally單獨成對使用時,try內產生一個異常之後,會立即跳轉到finally語句段。finally執行完畢之後,會繼續向上一層引發異常。注:若finally中的代碼引發了另一個異常或由於return,break,continue語法而終止,原來的異常將丟失且無法重新引發。

with語句

注:這一塊的內容不是很懂,這裡只舉簡單一例。

1
2
3
with open('myFile','r') as f:
for eachLine in f:
...

異常和sys模塊

另一種獲取異常信息的途徑是通過sys模塊中的exc_info()函數,此功能提供一個三元組的信息,多於我們單純用異常參數所能獲得的信息。

代碼示例:

1
2
3
4
5
6
7
8
try:
float('abc123')
except:
import sys
exc_tuple = sys.exc_info()

for item in exc_tuple:
print(item)

我們能從sys.exc_info()得到的元組中是:

  1. exc_type:異常類;
  2. exc_value:異常類的實例;
  3. exc_traceback:跟踪記錄對象

《Python核心編程》筆記(二)

https://justuno.github.io/2014/03/15/python-course-2/

作者

Justuno

发布于

2014-03-15

更新于

2015-09-29

许可协议

评论