python 速成集中營 — 預(yù)覽版

1. 計算部分

1.1. / 朝氓、// 宪彩、 %

除法(/)永遠返回一個浮點數(shù)休讳,如要使用 floor 除法 并且得到整數(shù)結(jié)果(丟掉任何小數(shù)部分)亲桥,你可以使用 // 運算符羡蛾;要計算余數(shù)你可以使用 %
使用 ** 運算符計算冪乘方

>>> 17 / 3  # classic division returns a float
5.666666666666667
>>>
>>> 17 // 3  # floor division discards the fractional part
5
>>> 17 % 3  # the % operator returns the remainder of the division
2
>>> 5 * 3 + 2  # result * divisor + remainder
17
>>> 5 ** 2  # 5 squared
25
>>> 2 ** 7  # 2 to the power of 7
128

1.2. 交互模式中枫夺,最近一個表達式的值賦給變量 _

>>> tax = 12.5 / 100
>>> price = 100.50
>>> price * tax
12.5625
>>> price + _          #這玩意有點秀
113.0625
>>> round(_, 2)
113.06

1.3. decimal——定點數(shù)和浮點數(shù)的數(shù)學(xué)運算

簡單mark一下啊活合,是精確計算用的
Decimal類型是在浮點類型的基礎(chǔ)上設(shè)計的,但是它在幾個地方上要優(yōu)于floating point:
1)Decimal類型可以非常精確地在計算機中存儲,而學(xué)過c++的都知道,浮點型在計算機中是無法精確存儲的,比如1.1和2.2在計算機中存儲后,運算(1.1+2.2)表達式的值結(jié)果會是3.3000000000000003;Decimal類型則不會出現(xiàn)這種情況雏婶。同樣,由于無法精確存儲,浮點型也就無法精確計算(相對于Decimal類型),可以再測試(0.1+0.1+0.1-0.3)兩種類型的計算結(jié)果白指。
2)Decimal類型會自動保留小數(shù)點后面不需要的0,以與輸入的精度相匹配,比如下面小程序中的例子:浮點型的1.20+1.30結(jié)果是2.5;而Decimal類型結(jié)果是2.50,這樣貌似比較人性化留晚。
3)Decimal類型可以根據(jù)需要自己設(shè)置小數(shù)點后精度。通過getcontext().prec = x (x為你想要的精度來設(shè)置,getcontext()函數(shù)下面再詳細介紹)告嘲。
4)Decimal類型有很強的管理功能,它能夠根據(jù)需要設(shè)置,來控制輸出的格式,得到或者忽略某類錯誤(如除0,可以設(shè)置忽略它,而得到一個Infinity的Decimal值)错维。

1.4. 行尾'\',表示:下一行在邏輯上是本行的后續(xù)內(nèi)容

字符串文本能夠分成多行。一種方法是使用三引號:"""..."""或者'''...'''橄唬。行尾換行符會被自動包含到字符串中赋焕,但是可以在行尾加上\來避免這個行為。下面的示例: 可以使用反斜杠為行結(jié)尾的連續(xù)字符串仰楚,它表示下一行在邏輯上是本行的后續(xù)內(nèi)容:

print("""\
Usage: thingy [OPTIONS]
     -h                        Display this usage message
     -H hostname               Hostname to connect to
""")
# 將生成以下輸出(注意隆判,沒有開始的第一行):
Usage: thingy [OPTIONS]
     -h                        Display this usage message
     -H hostname               Hostname to connect to

2. 字符串,列表

2.1. s[:i] + s[i:] 永遠等于s:

注意僧界,包含起始的字符侨嘀,不包含末尾的字符。

2.2. Python字符串不可以被更改 — 它們是 不可變的 捎泻。因此飒炎,賦值給字符串索引的位置會導(dǎo)致錯誤:

>>> word[0] = 'J'
  ...
TypeError: 'str' object does not support item assignment
>>> word[2:] = 'py'
  ...
TypeError: 'str' object does not support item assignment

2.3. 可以對切片賦值,此操作可以改變列表的尺寸笆豁,或清空它:

切片操作返回列表一個新的(淺)拷貝副本
list[3] = value,也可以看作是一個切片,所以會改變原列表

>>> letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
>>> letters
['a', 'b', 'c', 'd', 'e', 'f', 'g']
>>> # replace some values
>>> letters[2:5] = ['C', 'D', 'E']
>>> letters
['a', 'b', 'C', 'D', 'E', 'f', 'g']
>>> # now remove them
>>> letters[2:5] = []
>>> letters
['a', 'b', 'f', 'g']
>>> # clear the list by replacing all the elements with an empty list
>>> letters[:] = []
>>> letters
[]

2.4. 創(chuàng)建list

嘖嘖赤赊,有點秀

list = [None] * n
n為已知長度

for 語句就是這樣一個迭代器闯狱。list() 函數(shù)是另外一個( 迭代器 ),它從可迭代(對象)中創(chuàng)建列表:

>>> list(range(5))
[0, 1, 2, 3, 4]

3. 控制語句

3.1. 修改你迭代的序列(例如抛计,復(fù)制選擇項)哄孤,你可以迭代它的復(fù)本, 如for w in word[:]:

在迭代過程中修改迭代序列不安全(只有在使用鏈表這樣的可變序列時才會有這樣的情況)。使用切割標識就可以很方便的做到這一點:

>>> for w in words[:]:  # Loop over a slice copy of the entire list.
...     if len(w) > 6:
...         words.insert(0, w)
...
>>> words
['defenestrate', 'cat', 'window', 'defenestrate']

3.2. 循環(huán)可以有一個 else 子句

與循環(huán)一起使用時吹截,else 子句與 try 語句的 else 子句比與 if 語句的具有更多的共同點:try 語句的 else 子句在未出現(xiàn)異常時運行瘦陈,循環(huán)的 else 子句在未出現(xiàn) break 時運行凝危。更多關(guān)于 try 語句和異常的內(nèi)容,請參見 異常處理晨逝。

循環(huán)可以有一個 else 子句蛾默;它在循環(huán)迭代完整個列表(對于 for )或執(zhí)行條件為 false (對于 while)時執(zhí)行,但循環(huán)被 break 中止的情況下不會執(zhí)行捉貌。以下搜索素數(shù)的示例程序演示了這個子句:

>>> for n in range(2, 10):
...     for x in range(2, n):
...         if n % x == 0:
...             print(n, 'equals', x, '*', n//x)
...             break
...     else:
...         # loop fell through without finding a factor
...         print(n, 'is a prime number')
...
2 is a prime number
3 is a prime number
4 equals 2 * 2
5 is a prime number
6 equals 2 * 3
7 is a prime number
8 equals 2 * 4
9 equals 3 * 3

4. 函數(shù)

4.1. 用一個逗號結(jié)尾就可以禁止輸出換行:

或者 print(something, end='')

>>> a, b = 0, 1
>>> while b < 1000:
...     print(b, end=',')
...     a, b = b, a+b
...
1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,

4.2. 函數(shù)的參數(shù)

4.2.1. 默認參數(shù)

要求用戶確認的函數(shù)例子:

def ask_ok(prompt, retries=4, complaint='Yes or no, please!'):
    while True:
        ok = input(prompt)
        if ok in ('y', 'ye', 'yes'):
            return True
        if ok in ('n', 'no', 'nop', 'nope'):
            return False
        retries = retries - 1
        if retries < 0:
            raise OSError('uncooperative user')
        print(complaint)

默認值在函數(shù) 定義 作用域被解析

i = 5

def f(arg=i):  # f函數(shù)在這一行定義支鸡,默認參數(shù)被解析
    print(arg)

i = 6
f()

將會輸出 5
重要警告: 默認值只被賦值一次。
當默認值是可變對象時會有所不同趁窃,比如列表牧挣、字典或者大多數(shù)類的實例
例如醒陆,下面的函數(shù)在后續(xù)調(diào)用過程中會累積(前面)傳給它的參數(shù):

def f(a, L=[]):
    L.append(a)
    return L

print(f(1))
print(f(2))
print(f(3))

# 輸出
[1]
[1, 2]
[1, 2, 3]

如果你不想讓默認值在后續(xù)調(diào)用中累積瀑构,你可以像下面一樣定義函數(shù):

def f(a, L=None):
    if L is None:
        L = []
    L.append(a)
    return L

4.2.2. 可變參數(shù)列表

本質(zhì):元組封裝和序列拆封的一個結(jié)合
讓函數(shù)調(diào)用可變個數(shù)的參數(shù)。這些參數(shù)被包裝進一個元組(參見 元組和序列 )刨摩。在這些可變個數(shù)的參數(shù)之前检碗,可以有零到多個普通的參數(shù)。
這些可變參數(shù)是參數(shù)列表中的最后一個码邻,因為它們將把所有的剩余輸入?yún)?shù)傳遞給函數(shù)折剃。任何出現(xiàn)在 *args 后的參數(shù)是關(guān)鍵字參數(shù),這意味著像屋,他們只能被用作關(guān)鍵字怕犁,而不是位置參數(shù):

>>> def concat(*args, sep="/"):
...    return sep.join(args)
...
>>> concat("earth", "mars", "venus")
'earth/mars/venus'
>>> concat("earth", "mars", "venus", sep=".")  # sep只能是關(guān)鍵字參數(shù)!
'earth.mars.venus'

4.2.3. 關(guān)鍵字參數(shù)

引入一個形如 **name 的參數(shù)時己莺,它接收一個字典(參見 Mapping Types — dict )奏甫,該字典包含了所有未出現(xiàn)在形式參數(shù)列表中的關(guān)鍵字參數(shù)。
這里可能還會組合使用一個形如 *name (下一小節(jié)詳細介紹) 的形式參數(shù)凌受,它接收一個元組(下一節(jié)中會詳細介紹)阵子,包含了所有沒有出現(xiàn)在形式參數(shù)列表中的參數(shù)值(*name 必須在 **name 之前出現(xiàn))。

def cheeseshop(kind, *arguments, **keywords):
    print("-- Do you have any", kind, "?")
    print("-- I'm sorry, we're all out of", kind)
    for arg in arguments:
        print(arg)
    print("-" * 40)
    keys = sorted(keywords.keys())  # 對關(guān)鍵字排序
    for kw in keys:
        print(kw, ":", keywords[kw])

4.2.4. 參數(shù)列表的分拆—— * 拆開參數(shù)列表, ** 分拆字典為關(guān)鍵字參數(shù)

當你要傳遞的參數(shù)已經(jīng)是一個列表胜蛉,但要調(diào)用的函數(shù)卻接受分開一個個的參數(shù)值挠进。這時候你要把已有的列表拆開來。例如內(nèi)建函數(shù) range() 需要要獨立的 start誊册,stop 參數(shù)领突。你可以在調(diào)用函數(shù)時加一個 * 操作符來自動把參數(shù)列表拆開:

>>> list(range(3, 6))            # normal call with separate arguments
[3, 4, 5]
>>> args = [3, 6]
>>> list(range(*args))            # call with arguments unpacked from a list
[3, 4, 5]

以同樣的方式,可以使用 ** 操作符分拆關(guān)鍵字參數(shù)為字典:

>>> def parrot(voltage, state='a stiff', action='voom'):
...     print("-- This parrot wouldn't", action, end=' ')
...     print("if you put", voltage, "volts through it.", end=' ')
...     print("E's", state, "!")
...
>>> d = {"voltage": "four million", "state": "bleedin' demised", "action": "VOOM"}
>>> parrot(**d)
-- This parrot wouldn't VOOM if you put four million volts through it. E's bleedin' demised !

4.3. Lambda 形式

使用 lambda 表達式返回一個函數(shù)案怯,類似于嵌套函數(shù)定義君旦,lambda 形式可以從外部作用域引用變量:

>>> def make_incrementor(n):
...     return lambda x: x + n
...
>>> f = make_incrementor(42)
>>> f(0)
42
>>> f(1)   
43

或?qū)⒁粋€小函數(shù)作為參數(shù)傳遞:

>>> pairs = [(1, 'one'), (2, 'two'), (3, 'three'), (4, 'four')]
>>> pairs.sort(key=lambda pair: pair[1])  
>>> pairs
[(4, 'four'), (1, 'one'), (3, 'three'), (2, 'two')]

4.4. 函數(shù)的文檔字符串

第一行應(yīng)該是關(guān)于對象用途的簡介。簡短起見,不用明確的陳述對象名或類型金砍,因為它們可以從別的途徑了解到(除非這個名字碰巧就是描述這個函數(shù)操作的動詞)局蚀。這一行應(yīng)該以大寫字母開頭,以句號結(jié)尾恕稠。

如果文檔字符串有多行琅绅,第二行應(yīng)該空出來,與接下來的詳細描述明確分隔谱俭。接下來的文檔應(yīng)該有一或多段描述對象的調(diào)用約定奉件、邊界效應(yīng)等。

Python 的解釋器不會從多行的文檔字符串中去除縮進昆著,所以必要的時候應(yīng)當自己清除縮進县貌。這符合通常的習(xí)慣。第一行之后的第一個非空行決定了整個文檔的縮進格式凑懂。(我們不用第一行是因為它通常緊靠著起始的引號煤痕,縮進格式顯示的不清楚。)留白“相當于”是字符串的起始縮進接谨。每一行都不應(yīng)該有縮進摆碉,如果有縮進的話,所有的留白都應(yīng)該清除掉脓豪。留白的長度應(yīng)當?shù)扔跀U展制表符的寬度(通常是8個空格)巷帝。

以下是一個多行文檔字符串的示例:

>>> def my_function():
...     """Do nothing, but document it.
...
...     No, really, it doesn't do anything.
...     """
...     pass
...
>>> print(my_function.__doc__)
Do nothing, but document it.

    No, really, it doesn't do anything.

4.5. 編碼風格

對于 Python,PEP 8 引入了大多數(shù)項目遵循的風格指導(dǎo)扫夜。它給出了一個高度可讀楞泼,視覺友好的編碼風格。每個 Python 開發(fā)者都應(yīng)該讀一下笤闯,大多數(shù)要點都會對你有幫助:

  • 使用 4 空格縮進堕阔,而非 TAB

    在小縮進(可以嵌套更深)和大縮進(更易讀)之間,4空格是一個很好的折中颗味。TAB 引發(fā)了一些混亂超陆,最好棄用

  • 折行以確保其不會超過 79 個字符
    這有助于小顯示器用戶閱讀,也可以讓大顯示器能并排顯示幾個代碼文件

  • 使用空行分隔函數(shù)和類浦马,以及函數(shù)中的大塊代碼

  • 可能的話时呀,注釋獨占一行

  • 使用文檔字符串

  • 把空格放到操作符兩邊,以及逗號后面捐韩,但是括號里側(cè)不加空格:a = f(1, 2) + g(3, 4)

  • 統(tǒng)一函數(shù)和類命名
    推薦類名用 駝峰命名退唠, 函數(shù)和方法名用 小寫_和_下劃線』缧玻總是用 self 作為方法的第一個參數(shù)(關(guān)于類和方法的知識詳見 初識類

  • 不要使用花哨的編碼,如果你的代碼的目的是要在國際化環(huán)境屎债。Python 的默認情況下仅政,UTF-8垢油,甚至普通的 ASCII 總是工作的最好

  • 同樣,也不要使用非 ASCII 字符的標識符圆丹,除非是不同語種的會閱讀或者維護代碼滩愁。

5. 數(shù)據(jù)結(jié)構(gòu)

5.1. 列表level up

  • list.append(x):
    把一個元素添加到列表的結(jié)尾
  • list.extend(L):
    將一個給定列表中的所有元素都添加到另一個列表中
  • list.insert(i, x):
    在指定位置插入一個元素
  • list.remove(x):
    刪除列表中值為 x 的第一個元素。如果沒有這樣的元素辫封,就會返回一個錯誤硝枉。
  • list.pop([i]):
    如果沒有指定索引,a.pop() 返回最后一個元素
  • list.clear():
    從列表中刪除所有元素
  • list.index(x):
    返回列表中第一個值為 x 的元素的索引倦微。如果沒有匹配的元素就會返回一個錯誤妻味。
  • list.count(x):
    返回 x 在列表中出現(xiàn)的次數(shù)。
  • list.sort():
    對列表中的元素就地進行排序欣福。
  • list.reverse():
    就地倒排
  • list.copy():
    返回列表的一個淺拷貝责球。等同于 a[:]。

5.1.1. 把列表當作堆棧使用

堆棧作為特定的數(shù)據(jù)結(jié)構(gòu)拓劝,最先進入的元素最后一個被釋放(后進先出)雏逾。用 append() 方法可以把一個元素添加到堆棧頂。用不指定索引的 pop()方法可以把一個元素從堆棧頂釋放出來郑临。例如:

5.1.2. 把列表當作隊列使用

隊列作為特定的數(shù)據(jù)結(jié)構(gòu)栖博,最先進入的元素最先釋放(先進先出)。不過厢洞,列表這樣用效率不高仇让。
要實現(xiàn)隊列,使用 collections.deque犀变,它為在首尾兩端快速插入和刪除而設(shè)計妹孙。例如:

>>> from collections import deque
>>> queue = deque(["Eric", "John", "Michael"])
>>> queue.append("Terry")           # Terry arrives
>>> queue.append("Graham")          # Graham arrives
>>> queue.popleft()                 # The first to arrive now leaves
'Eric'
>>> queue.popleft()                 # The second to arrive now leaves
'John'
>>> queue                           # Remaining queue in order of arrival
deque(['Michael', 'Terry', 'Graham'])

5.2. del 語句

從列表中按給定的索引而不是值來刪除一個子項

>>> a = [-1, 1, 66.25, 333, 333, 1234.5]
>>> del a[0]
>>> a
[1, 66.25, 333, 333, 1234.5]
>>> del a[2:4]
>>> a
[1, 66.25, 1234.5]
>>> del a[:]
>>> a
[]
>>> del a  # 也可以刪除整個變量

5.3. 元組

>>> t = 12345, 54321, 'hello!'
>>> t[0]
12345
>>> t
(12345, 54321, 'hello!')
>>> # Tuples may be nested:
... u = t, (1, 2, 3, 4, 5) # 封裝成元組
>>> u
((12345, 54321, 'hello!'), (1, 2, 3, 4, 5))

一對空的括號可以創(chuàng)建空元組
創(chuàng)建一個單元素元組可以在值后面跟一個逗號(在括號中放入一個單值不夠明確)

>>> empty = ()
>>> singleton = 'hello',    # <-- note trailing comma
>>> singleton
('hello',)

元組拆分:x, y, z = t

5.4. 集合

集合是一個無序不重復(fù)元素的集』裰Γ基本功能包括關(guān)系測試和消除重復(fù)元素蠢正。集合對象還支持 union(聯(lián)合),intersection(交)省店,difference(差)和 sysmmetric difference(對稱差集)等數(shù)學(xué)運算嚣崭。
注意:想要創(chuàng)建空集合,你必須使用 set() 而不是 {}懦傍。后者用于創(chuàng)建空字典雹舀。

>>> basket = {'apple', 'orange', 'apple', 'pear', 'orange', 'banana'}
>>> print(basket)                      # show that duplicates have been removed
{'orange', 'banana', 'pear', 'apple'}
>>> 'orange' in basket                 # fast membership testing
True
>>> 'crabgrass' in basket
False

>>> # Demonstrate set operations on unique letters from two words
...
>>> a = set('abracadabra')
>>> b = set('alacazam')
>>> a                                  # unique letters in a
{'a', 'r', 'b', 'c', 'd'}
>>> a - b                              # letters in a but not in b
{'r', 'd', 'b'}
>>> a | b                              # letters in either a or b
{'a', 'c', 'r', 'd', 'b', 'm', 'z', 'l'}
>>> a & b                              # letters in both a and b
{'a', 'c'}
>>> a ^ b                              # letters in a or b but not both
{'r', 'd', 'b', 'm', 'z', 'l'}

類似 列表推導(dǎo)式,這里有一種集合推導(dǎo)式語法:

>>> a = {x for x in 'abracadabra' if x not in 'abc'}
>>> a
{'r', 'd'}

5.5. 字典

無序的鍵: 值對 (key:value 對)集合粗俱,鍵必須是互不相同的(在同一個字典之內(nèi))说榆。一對大括號創(chuàng)建一個空的字典: {} 。初始化列表時,在大括號內(nèi)放置一組逗號分隔的鍵:值對签财,這也是字典輸出的方式串慰。
對一個字典執(zhí)行 list(d.keys()) 將返回一個字典中所有關(guān)鍵字組成的無序列表(如果你想要排序,只需使用 sorted(d.keys()) )唱蒸。使用 in 關(guān)鍵字可以檢查字典中是否存在某個關(guān)鍵字(指字典)邦鲫。

  • 直接從 key-value 對中創(chuàng)建字典:
>>> dict([('sape', 4139), ('guido', 4127), ('jack', 4098)])
{'sape': 4139, 'jack': 4098, 'guido': 4127}
  • 字典推導(dǎo)式可以從任意的鍵值表達式中創(chuàng)建字典:
>>> {x: x**2 for x in (2, 4, 6)}
{2: 4, 4: 16, 6: 36}
  • 通過關(guān)鍵字參數(shù)指定 key-value 對:
>>> dict(sape=4139, guido=4127, jack=4098)
{'sape': 4139, 'jack': 4098, 'guido': 4127}

5.6. 循環(huán)技巧

  • 在字典中循環(huán)時,關(guān)鍵字和對應(yīng)的值可以使用items() 方法同時解讀出來:
>>> knights = {'gallahad': 'the pure', 'robin': 'the brave'}
>>> for k, v in knights.items():
...     print(k, v)
  • 同時循環(huán)兩個或更多的序列神汹,可以使用 zip() 整體打包:
>>> questions = ['name', 'quest', 'favorite color']
>>> answers = ['lancelot', 'the holy grail', 'blue']
>>> for q, a in zip(questions, answers):
...     print('What is your {0}?  It is {1}.'.format(q, a))
  • 逆向循環(huán)序列的話庆捺,先正向定位序列,然后調(diào)用 reversed() 函數(shù):
>>> for i in reversed(range(1, 10, 2)):
...     print(i)
  • 要按排序后的順序循環(huán)序列的話屁魏,使用 sorted() 函數(shù)
>>> basket = ['apple', 'orange', 'apple', 'pear', 'orange', 'banana']
>>> for f in sorted(set(basket)):
...     print(f)
  • 要在循環(huán)內(nèi)部修改正在遍歷的序列(例如復(fù)制某些元素)滔以,建議您首先制作副本,使用切片表示法
>>> words = ['cat', 'window', 'defenestrate']
>>> for w in words[:]:  # Loop over a slice copy of the entire list.
...     if len(w) > 6:
...         words.insert(0, w)

5.7. 深入條件控制

  • 比較操作符 innot in 審核值是否在一個區(qū)間之內(nèi)。操作符 isis not 比較兩個對象是否相同
  • 比較操作可以傳遞蚁堤。例如a < b == c 審核是否 a 小于b 并且b 等于c
  • 比較操作可以通過邏輯操作符 andor組合醉者,比較的結(jié)果可以用 not來取反義。這些操作符的優(yōu)先級又低于比較操作符披诗,在它們之中撬即,not 具有最高的優(yōu)先級,or優(yōu)先級最低呈队,所以 A and not B or C 等于 (A and (notB)) or C

5.8 比較序列和其它類型

(1, 2, 3)              < (1, 2, 4)
[1, 2, 3]              < [1, 2, 4]
'ABC' < 'C' < 'Pascal' < 'Python'  # 字符串的字典序按照單字符的 ASCII 順序
(1, 2, 3, 4)           < (1, 2, 4)
(1, 2)                 < (1, 2, -1)  # 如果一個序列是另一個序列的初始子序列剥槐,較短的一個序列就小于另一個
(1, 2, 3)             == (1.0, 2.0, 3.0)  # 混合數(shù)值類型是通過它們的數(shù)值進行比較的,所以 0 是等于 0.0
(1, 2, ('aa', 'ab'))   < (1, 2, ('abc', 'a'), 4)

6. 模塊

6.1. 模塊載入

出于性能考慮宪摧,每個模塊在每個解釋器會話中只導(dǎo)入一遍粒竖。因此,如果你修改了你的模塊几于,需要重啟解釋器蕊苗;或者,如果你就是想交互式的測試這么一個模塊沿彭,可以用 imp.reload() 重新加載朽砰,例如 import imp; imp.reload(modulename)

6.2. 模塊的搜索路徑

導(dǎo)入一個叫 spam 的模塊時喉刘,解釋器先在當前目錄中搜索名為 spam.py 的文件瞧柔。如果沒有找到的話,接著會到 sys.path 變量中給出的目錄列表中查找睦裳。 sys.path 變量的初始值來自如下:

  • 輸入腳本的目錄(當前目錄)造锅。
  • 環(huán)境變量 PYTHONPATH 表示的目錄列表中搜索
    (這和 shell 變量 PATH 具有一樣的語法,即一系列目錄名的列表)廉邑。
  • Python 默認安裝路徑中搜索哥蔚。
  • 在支持符號連接的文件系統(tǒng)中倒谷,輸入的腳本所在的目錄是符號連接指向的目錄。 換句話說也就是包含符號鏈接的目錄不會被加到目錄搜索路徑中肺素。

變量 sys.path 是解釋器模塊搜索路徑的字符串列表恨锚。它由環(huán)境變量 PYTHONPATH 初始化宇驾,如果沒有設(shè)定 PYTHONPATH 倍靡,就由內(nèi)置的默認值初始化。你可以用標準的字符串操作修改它:

>>> import sys
>>> sys.path.append('/ufs/guido/lib/python')

6.3. dir() 函數(shù)

內(nèi)置函數(shù) dir() 用于按模塊名搜索模塊定義课舍,它返回一個字符串類型的存儲列表:

>>> import fibo, sys
>>> dir(fibo)
['__name__', 'fib', 'fib2']

無參數(shù)調(diào)用時塌西,dir() 函數(shù)返回當前定義的命名:

>>> a = [1, 2, 3, 4, 5]
>>> import fibo
>>> fib = fibo.fib
>>> dir()
['__builtins__', '__doc__', '__file__', '__name__', 'a', 'fib', 'fibo', 'sys']

該列表列出了所有類型的名稱:變量,模塊筝尾,函數(shù)捡需,等等。
dir() 不會列出內(nèi)置函數(shù)和變量名筹淫。如果你想列出這些內(nèi)容站辉,它們在標準模塊 builtins 中定義:

>>> import builtins
>>> dir(builtins)  

6.4. 包

一個聲音處理的模塊集,目錄結(jié)構(gòu)如下:

sound/                          Top-level package
      __init__.py               Initialize the sound package
      formats/                  Subpackage for file format conversions
              __init__.py
              wavread.py
              wavwrite.py
              aiffread.py
              aiffwrite.py
              auread.py
              auwrite.py
              ...
      effects/                  Subpackage for sound effects
              __init__.py
              echo.py
              surround.py
              reverse.py
              ...
      filters/                  Subpackage for filters
              __init__.py
              equalizer.py
              vocoder.py
              karaoke.py
              ...

當導(dǎo)入這個包時损姜,Python 通過 sys.path 搜索路徑查找包含這個包的子目錄饰剥。
為了讓 Python 將目錄當做內(nèi)容包,目錄中必須包含 __init__.py 文件摧阅。最簡單的情況下汰蓉,只需要一個空的 __init__.py 文件即可。當然它也可以執(zhí)行包的初始化代碼棒卷,或者定義稍后介紹的 __all__ 變量顾孽。

6.4.1. 導(dǎo)入包的幾種方式:

# 加載 echo 子模塊
echo.echofilter(input, output, delay=0.7, atten=4)
# 直接導(dǎo)入函數(shù)或變量
from sound.effects.echo import echofilter

6.4.2. 從 * 導(dǎo)入包

提供一個明確的包索引。import 語句按如下條件進行轉(zhuǎn)換:執(zhí)行 from package import * 時比规,如果包中的 __init__.py 代碼定義了一個名為 __all__ 的列表若厚,就會按照列表中給出的模塊名進行導(dǎo)入。新版本的包發(fā)布時作者可以任意更新這個列表蜒什。如果包作者不想 import * 的時候?qū)胨麄兊陌兴心K测秸,那么也可能會決定不支持它( import * )。例如吃谣, sound/effects/__init__.py 這個文件可能包括如下代碼:

__all__ = ["echo", "surround", "reverse"]

這意味著from sound.effects import 語句會從 sound 包中導(dǎo)入以上三個已命名的子模塊乞封。

6.4.3. 包內(nèi)引用

可以用這樣的形式from module import name 來寫顯式的相對位置導(dǎo)入。那些顯式相對導(dǎo)入用點號標明關(guān)聯(lián)導(dǎo)入當前和上級包岗憋。以 surround 模塊為例肃晚,你可以這樣用:

from . import echo
from .. import formats
from ..filters import equalizer

需要注意的是顯式或隱式相對位置導(dǎo)入都基于當前模塊的命名。因為主模塊的名字總是"__main__"仔戈,Python 應(yīng)用程序的主模塊應(yīng)該總是用絕對導(dǎo)入关串。

7. 輸入和輸出

7.1. 格式化輸出

這里有兩種大相徑庭地輸出值方法:表達式語句print() 函數(shù)(第三種訪求是使用文件對象的 write() 方法拧廊,標準文件輸出可以參考 sys.stdout,詳細內(nèi)容參見庫參考手冊)晋修。
str.format() 方法提供了豐富的格式控制吧碾。
如何將值轉(zhuǎn)化為字符串?Python 有辦法將任意值轉(zhuǎn)為字符串:將它傳入 repr()str() 函數(shù)墓卦。
函數(shù) str() 用于將值轉(zhuǎn)化為適于人閱讀的形式倦春,而 repr() 轉(zhuǎn)化為供解釋器讀取的形式(如果沒有等價的語法,則會發(fā)生 SyntaxError 異常)某對象沒有適于人閱讀的解釋形式的話落剪,str() 會返回與 repr()等同的值睁本。

7.2. str的一些方法

  • str.rjust() 方法,它把字符串輸出到一列忠怖,并通過向左側(cè)填充空格來使其右對齊呢堰。類似的方法還有 str.ljust()str.center()。這些函數(shù)只是輸出新的字符串凡泣,并不改變什么枉疼。如果輸出的字符串太長,它們也不會截斷它鞋拟,而是原樣輸出骂维。如果你確實需要截斷它,可以使用切割操作严卖,例如:x.ljust(n)[:n]席舍。
  • str.zfill() 它用于向數(shù)值的字符串表達左側(cè)填充 0。該函數(shù)可以正確理解正負號:
>>> '12'.zfill(5)
'00012'
>>> '-3.14'.zfill(7)
'-003.14'
>>> '3.14159265359'.zfill(5)
'3.14159265359'
>>> print('We are the {} who say "{}!"'.format('knights', 'Ni'))
We are the knights who say "Ni!"

大括號和其中的字符會被替換成傳入 str.format() 的參數(shù)哮笆。大括號中的數(shù)值指明使用傳入 str.format()方法的對象中的哪一個:

>>> print('{0} and {1}'.format('spam', 'eggs'))
spam and eggs
>>> print('{1} and {0}'.format('spam', 'eggs'))
eggs and spam

如果在 str.format() 調(diào)用時使用關(guān)鍵字參數(shù)来颤,可以通過參數(shù)名來引用值:

>>> print('This {food} is {adjective}.'.format(
...       food='spam', adjective='absolutely horrible'))
This spam is absolutely horrible.

位置參數(shù)和關(guān)鍵字參數(shù)可以隨意組合:

>>> print('The story of {0}, {1}, and {other}.'.format('Bill', 'Manfred',
                                                       other='Georg'))
The story of Bill, Manfred, and Georg.

'!a' (應(yīng)用 ascii()),'!s' (應(yīng)用 str() )和 '!r' (應(yīng)用 repr() )可以在格式化之前轉(zhuǎn)換值:

>>> import math
>>> print('The value of PI is approximately {}.'.format(math.pi))
The value of PI is approximately 3.14159265359.
>>> print('The value of PI is approximately {!r}.'.format(math.pi))
The value of PI is approximately 3.141592653589793.

字段名后允許可選的':' 和格式指令稠肘。下例將 Pi 轉(zhuǎn)為三位精度福铅。

>>> import math
>>> print('The value of PI is approximately {0:.3f}.'.format(math.pi))
The value of PI is approximately 3.142.

在字段后的 ':' 后面加一個整數(shù)會限定該字段的最小寬度,這在美化表格時很有用:

>>> table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 7678}
>>> for name, phone in table.items():
...     print('{0:10} ==> {1:10d}'.format(name, phone))
...
Jack       ==>       4098
Dcab       ==>       7678
Sjoerd     ==>       4127

可以用命名來引用被格式化的變量而不是位置项阴。傳入一個字典滑黔,用中括號( '[]')訪問它的鍵:

>>> table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 8637678}
>>> print('Jack: {0[Jack]:d}; Sjoerd: {0[Sjoerd]:d}; '
          'Dcab: {0[Dcab]:d}'.format(table))
Jack: 4098; Sjoerd: 4127; Dcab: 8637678

也可以用 ‘**’ 標志將這個字典以關(guān)鍵字參數(shù)的方式傳入:

>>> table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 8637678}
>>> print('Jack: {Jack:d}; Sjoerd: {Sjoerd:d}; Dcab: {Dcab:d}'.format(**table))
Jack: 4098; Sjoerd: 4127; Dcab: 8637678

這種方式與新的內(nèi)置函數(shù) vars() 組合使用非常有效。該函數(shù)返回包含所有局部變量的字典环揽。

要進一步了解字符串格式化方法 str.format()略荡,參見 格式字符串語法

7.2. 文件讀寫

函數(shù) open() 返回 文件對象歉胶,通常的用法需要兩個參數(shù):open(filename, mode)汛兜。

>>> f = open('workfile', 'w')

第一個參數(shù)是一個含有文件名的字符串。第二個參數(shù)也是一個字符串通今,含有描述如何使用該文件的幾個字符粥谬。mode 為 'r' 時表示只是讀取文件肛根;'w' 表示只是寫入文件(已經(jīng)存在的同名文件將被刪掉);'a' 表示打開文件進行追加漏策,寫入到文件中的任何數(shù)據(jù)將自動添加到末尾派哲。 'r+' 表示打開文件進行讀取和寫入。mode 參數(shù)是可選的掺喻,默認為 'r'芭届。

通常,文件以 文本 打開巢寡,這意味著喉脖,你從文件讀出和向文件寫入的字符串會被特定的編碼方式(默認是UTF-8)編碼。模式后面的 'b' 以 二進制模式 打開文件:數(shù)據(jù)會以字節(jié)對象的形式讀出和寫入抑月。這種模式應(yīng)該用于所有不包含文本的文件。

在文本模式下舆蝴,讀取時默認會將平臺有關(guān)的行結(jié)束符(Unix上是 \n , Windows上是 \r\n)轉(zhuǎn)換為 \n谦絮。在文本模式下寫入時,默認會將出現(xiàn)的 \n 轉(zhuǎn)換成平臺有關(guān)的行結(jié)束符洁仗。這種暗地里的修改對 ASCII 文本文件沒有問題层皱,但會損壞 JPEG 或 EXE 這樣的二進制文件中的數(shù)據(jù)。使用二進制模式讀寫此類文件時要特別小心赠潦。

7.2.1. 文件對象方法

要讀取文件內(nèi)容叫胖,需要調(diào)用f.read(size),該方法讀取若干數(shù)量的數(shù)據(jù)并以字符串形式返回其內(nèi)容她奥,size 是可選的數(shù)值瓮增,指定字符串長度。
如果沒有指定 size 或者指定為負數(shù)哩俭,就會讀取并返回整個文件绷跑。當文件大小為當前機器內(nèi)存兩倍時,就會產(chǎn)生問題凡资。反之砸捏,會盡可能按比較大的 * 讀取和返回數(shù)據(jù)。如果到了文件末尾隙赁,f.read() 會返回一個空字符串(''):

>>> f.read()
'This is the entire file.\n'
>>> f.read()
''

f.readline()從文件中讀取單獨一行垦藏,字符串結(jié)尾會自動加上一個換行符(\n ),只有當文件最后一行沒有以換行符結(jié)尾時伞访,這一操作才會被忽略掂骏。

  • 如果f.readline() 返回一個空字符串,那就表示到達了文件末尾
  • 如果是一個空行咐扭,就會描述為 '\n'芭挽,一個只包含換行符的字符串:
>>> f.readline()
'This is the first line of the file.\n'
>>> f.readline()
'Second line of the file\n'
>>> f.readline()
''

把文件中的所有行讀到一個列表中滑废,可以使用 list(f) 或者f.readlines()

f.write(string) 方法將 string 的內(nèi)容寫入文件袜爪,并返回寫入字符的長度:

>>> f.write('This is a test\n')
15

想要寫入其他非字符串內(nèi)容蠕趁,首先要將它轉(zhuǎn)換為字符串。

當你使用完一個文件時辛馆,調(diào)用 f.close() 方法就可以關(guān)閉它并釋放其占用的所有系統(tǒng)資源俺陋。 在調(diào)用 f.close() 方法后,試圖再次使用文件對象將會自動失敗昙篙。
用關(guān)鍵字 with 處理文件對象是個好習(xí)慣腊状。它的先進之處在于文件用完后會自動關(guān)閉,就算發(fā)生異常也沒關(guān)系苔可。它是 try-finally 塊的簡寫:

>>> with open('workfile', 'r') as f:
...     read_data = f.read()
>>> f.closed
True

7.2.2. 使用 json 存儲結(jié)構(gòu)化數(shù)據(jù)

Python 允許你使用常用的數(shù)據(jù)交換格式 JSON(JavaScript Object Notation)绰播。標準模塊 json 可以接受 Python 數(shù)據(jù)結(jié)構(gòu)嚣伐,并將它們轉(zhuǎn)換為字符串表示形式;此過程稱為 序列化。從字符串表示形式重新構(gòu)建數(shù)據(jù)結(jié)構(gòu)稱為 反序列化陪蜻。序列化和反序列化的過程中豫领,表示該對象的字符串可以存儲在文件或數(shù)據(jù)中闪湾,也可以通過網(wǎng)絡(luò)連接傳送給遠程的機器昵时。
如果你有一個對象 x,你可以用簡單的一行代碼查看其 JSON 字符串表示形式:

>>> json.dumps([1, 'simple', 'list'])
'[1, "simple", "list"]'

dumps() 函數(shù)的另外一個變體 dump()湾蔓,直接將對象序列化到一個文件瘫析。所以如果 f 是為寫入而打開的一個 文件對象,我們可以這樣做:

json.dump(x, f)

為了重新解碼對象默责,如果 f 是為讀取而打開的 文件對象:

x = json.load(f)

這種簡單的序列化技術(shù)可以處理列表和字典贬循,但序列化任意類實例為 JSON 需要一點額外的努力。 json 模塊的手冊對此有詳細的解釋傻丝。

7.2.3. pickle - pickle 模塊

JSON 不同甘有,pickle 是一個協(xié)議,它允許任意復(fù)雜的 Python 對象的序列化葡缰。因此亏掀,它只能用于 Python 而不能用來與其他語言編寫的應(yīng)用程序進行通信。默認情況下它也是不安全的:如果數(shù)據(jù)由熟練的攻擊者精心設(shè)計泛释, 反序列化來自一個不受信任源的 pickle 數(shù)據(jù)可以執(zhí)行任意代碼滤愕。

8. 錯誤和異常

Python 中(至少)有兩種錯誤:語法錯誤和異常( syntax errorsexceptions )。

8.1. 語法錯誤

語法錯誤怜校,也被稱作解析錯誤间影。
這是最常見的錯誤,往往是由于缺少冒號或者括號等引起茄茁。

>>> while True print('Hello world')
  File "<stdin>", line 1, in ?
    while True print('Hello world')
                   ^
SyntaxError: invalid syntax

語法分析器指出錯誤行魂贬,并且在檢測到錯誤的位置前面顯示一個小“箭頭”巩割。 錯誤是由箭頭 前面 的標記引起的(或者至少是這么檢測的): 這個例子中,函數(shù) print() 被發(fā)現(xiàn)存在錯誤付燥,因為它前面少了一個冒號( ':' )宣谈。 錯誤會輸出文件名和行號。

8.2. 異常

即使一條語句或表達式在語法上是正確的键科,當試圖執(zhí)行它時也可能會引發(fā)錯誤闻丑。運行期檢測到的錯誤稱為 異常,并且程序不會無條件的崩潰:

>>> 10 * (1/0)
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
ZeroDivisionError: int division or modulo by zero
>>> 4 + spam*3
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
NameError: name 'spam' is not defined
>>> '2' + 2
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
TypeError: Can't convert 'int' object to str implicitly

錯誤信息的最后一行指出發(fā)生了什么錯誤勋颖。異常也有不同的類型嗦嗡,異常類型做為錯誤信息的一部分顯示出來:示例中的異常分別為 零除錯誤( ZeroDivisionError ) ,命名錯誤( NameError) 和 類型錯誤( TypeError )饭玲。打印錯誤信息時侥祭,異常的類型作為異常的內(nèi)置名顯示。對于所有的內(nèi)置異常都是如此咱枉,不過用戶自定義異常就不一定了(盡管這是一個很有用的約定)卑硫。標準異常名是內(nèi)置的標識(沒有保留關(guān)鍵字)。

這一行后一部分是關(guān)于該異常類型的詳細說明蚕断,這意味著它的內(nèi)容依賴于異常類型。

錯誤信息的前半部分以堆棧的形式列出異常發(fā)生的位置入挣。通常在堆棧中列出了源代碼行亿乳,然而,來自標準輸入的源碼不會顯示出來径筏。

內(nèi)置的異常 列出了內(nèi)置異常和它們的含義葛假。

8.3. 異常處理

通過編程處理選擇的異常是可行的∽烫瘢看一下下面的例子:它會一直要求用戶輸入聊训,直到輸入一個合法的整數(shù)為止,但允許用戶中斷這個程序(使用 Control-C 或系統(tǒng)支持的任何方法)恢氯。注意:用戶產(chǎn)生的中斷會引發(fā)一個 KeyboardInterrupt 異常带斑。

>>> while True:
...     try:
...         x = int(input("Please enter a number: "))
...         break
...     except ValueError:
...         print("Oops!  That was no valid number.  Try again...")
...

8.3.1 try - except - else 語句

try 語句按如下方式工作。

  • 首先勋拟,執(zhí)行 try 子句 (在 tryexcept 關(guān)鍵字之間的部分)勋磕。

  • 如果沒有異常發(fā)生, except 子句 在 try 語句執(zhí)行完畢后就被忽略了敢靡。

  • 如果在 try 子句執(zhí)行過程中發(fā)生了異常挂滓,那么該子句其余的部分就會被忽略。
    如果異常匹配于 except 關(guān)鍵字后面指定的異常類型啸胧,就執(zhí)行對應(yīng)的except子句赶站。然后繼續(xù)執(zhí)行 try 語句之后的代碼幔虏。

  • 如果發(fā)生了一個異常,在 except 子句中沒有與之匹配的分支贝椿,它就會傳遞到上一級 try 語句中想括。
    如果最終仍找不到對應(yīng)的處理語句,它就成為一個 未處理異常团秽,終止程序運行主胧,顯示提示信息。

一個 try 語句可能包含多個 except 子句习勤,分別指定處理不同的異常踪栋。至多只會有一個分支被執(zhí)行。異常處理程序只會處理對應(yīng)的 try 子句中發(fā)生的異常图毕,在同一個 try 語句中夷都,其他子句中發(fā)生的異常則不作處理。一個 except 子句可以在括號中列出多個異常的名字予颤,例如:

... except (RuntimeError, TypeError, NameError):
...     pass

最后一個 except 子句可以省略異常名稱囤官,以作為通配符使用。你需要慎用此法蛤虐,因為它會輕易隱藏一個實際的程序錯誤党饮!可以使用這種方法打印一條錯誤信息,然后重新拋出異常(允許調(diào)用者處理這個異常):

import sys

try:
    f = open('myfile.txt')
    s = f.readline()
    i = int(s.strip())
except OSError as err:
    print("OS error: {0}".format(err))
except ValueError:
    print("Could not convert data to an integer.")
except:
    print("Unexpected error:", sys.exc_info()[0])
    raise

tryexcept 語句可以帶有一個 else子句驳庭,該子句只能出現(xiàn)在所有 except 子句之后刑顺。當 try 語句沒有拋出異常時,需要執(zhí)行一些代碼饲常,可以使用這個子句蹲堂。例如:

for arg in sys.argv[1:]:
    try:
        f = open(arg, 'r')
    except IOError:
        print('cannot open', arg)
    else:
        print(arg, 'has', len(f.readlines()), 'lines')
        f.close()

使用 else 子句比在 try 子句中附加代碼要好,因為這樣可以避免 tryexcept 意外的截獲本來不屬于它們保護的那些代碼拋出的異常贝淤。

8.3.2 異常的參數(shù)

發(fā)生異常時柒竞,可能會有一個附屬值,作為異常的 參數(shù) 存在播聪。這個參數(shù)是否存在朽基、是什么類型,依賴于異常的類型犬耻。

在異常名(列表)之后踩晶,也可以為 except 子句指定一個變量。這個變量綁定于一個異常實例枕磁,它存儲在 instance.args 的參數(shù)中渡蜻。
為了方便起見,異常實例定義了 __str __() ,這樣就可以直接訪問過打印參數(shù)而不必引用 .args茸苇。這種做法不受鼓勵排苍。相反,更好的做法是給異常傳遞一個參數(shù)(如果要傳遞多個參數(shù)学密,可以傳遞一個元組)淘衙,把它綁定到 message 屬性。一旦異常發(fā)生腻暮,它會在拋出前綁定所有指定的屬性彤守。

>>> try:
...    raise Exception('spam', 'eggs')
... except Exception as inst:
...    print(type(inst))    # the exception instance
...    print(inst.args)     # arguments stored in .args
...    print(inst)          # __str__ allows args to be printed directly,
...                         # but may be overridden in exception subclasses
...    x, y = inst.args     # unpack args
...    print('x =', x)
...    print('y =', y)
...
<class 'Exception'>
('spam', 'eggs')
('spam', 'eggs')
x = spam
y = eggs

對于那些未處理的異常,如果一個它們帶有參數(shù)哭靖,那么就會被作為異常信息的最后部分(“詳情”)打印出來具垫。

異常處理器不僅僅處理那些在 try 子句中立刻發(fā)生的異常,也會處理那些 try 子句中調(diào)用的函數(shù)內(nèi)部發(fā)生的異常试幽。

8.4. 拋出異常

raise 語句允許程序員強制拋出一個指定的異常筝蚕。例如:

>>> raise NameError('HiThere')
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
NameError: HiThere

要拋出的異常由 raise 的唯一參數(shù)標識。它必需是一個異常實例或異常類(繼承自 Exception 的類)铺坞。

如果你需要明確一個異常是否拋出起宽,但不想處理它,raise 語句可以讓你很簡單的重新拋出該異常:

>>> try:
...     raise NameError('HiThere')
... except NameError:
...     print('An exception flew by!')
...     raise
...
An exception flew by!
Traceback (most recent call last):
  File "<stdin>", line 2, in ?
NameError: HiThere

8.5. 用戶自定義異常

在程序中可以通過創(chuàng)建新的異常類型來命名自己的異常济榨。異常類通常應(yīng)該直接或間接的從 Exception 類派生坯沪,例如:

>>> class MyError(Exception):
...     def __init__(self, value):
...         self.value = value
...     def __str__(self):
...         return repr(self.value)
...
>>> try:
...     raise MyError(2*2)
... except MyError as e:
...     print('My exception occurred, value:', e.value)
...
My exception occurred, value: 4
>>> raise MyError('oops!')
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
__main__.MyError: 'oops!'

在這個例子中,Exception 默認的 init() 被覆蓋擒滑。新的方式簡單的創(chuàng)建 value 屬性屏箍。這就替換了原來創(chuàng)建 args 屬性的方式。

異常類中可以定義任何其它類中可以定義的東西橘忱,但是通常為了保持簡單,只在其中加入幾個屬性信息卸奉,以供異常處理句柄提取钝诚。如果一個新創(chuàng)建的模塊中需要拋出幾種不同的錯誤時,一個通常的作法是為該模塊定義一個異抽茫基類凝颇,然后針對不同的錯誤類型派生出對應(yīng)的異常子類:

class Error(Exception):
    """Base class for exceptions in this module."""
    pass

class InputError(Error):
    """Exception raised for errors in the input.

    Attributes:
        expression -- input expression in which the error occurred
        message -- explanation of the error
    """

    def __init__(self, expression, message):
        self.expression = expression
        self.message = message

class TransitionError(Error):
    """Raised when an operation attempts a state transition that's not
    allowed.

    Attributes:
        previous -- state at beginning of transition
        next -- attempted new state
        message -- explanation of why the specific transition is not allowed
    """

    def __init__(self, previous, next, message):
        self.previous = previous
        self.next = next
        self.message = message

8.6. 定義清理行為

try 語句還有另一個可選的子句,目的在于定義在任何情況下都一定要執(zhí)行的功能疹鳄。例如:

>>> def divide(x, y):
...     try:
...         result = x / y
...     except ZeroDivisionError:
...         print("division by zero!")
...     else:
...         print("result is", result)
...     finally:
...         print("executing finally clause")
...
>>> divide(2, 1)
result is 2
executing finally clause
>>> divide(2, 0)
division by zero!
executing finally clause
>>> divide("2", "1")
executing finally clause
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
  File "<stdin>", line 3, in divide
TypeError: unsupported operand type(s) for /: 'str' and 'str'

不管有沒有發(fā)生異常拧略,finally子句 在程序離開 try 后都一定會被執(zhí)行。當 try 語句中發(fā)生了未被 except 捕獲的異常(或者它發(fā)生在 exceptelse 子句中)瘪弓,在 finally 子句執(zhí)行完后它會被重新拋出垫蛆。 try 語句經(jīng)由 breakcontinuereturn 語句退 出也一樣會執(zhí)行 finally 子句。

finally 子句在任何情況下都會執(zhí)行袱饭。TypeError 在兩個字符串相除的時候拋出川无,未被 except 子句捕獲,因此在 finally 子句執(zhí)行完畢后重新拋出虑乖。

在真實場景的應(yīng)用程序中懦趋,finally 子句用于釋放外部資源(文件 或網(wǎng)絡(luò)連接之類的),無論它們的使用過程中是否出錯疹味。

what's more

仅叫。。糙捺。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末诫咱,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子继找,更是在濱河造成了極大的恐慌遂跟,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,122評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件婴渡,死亡現(xiàn)場離奇詭異幻锁,居然都是意外死亡,警方通過查閱死者的電腦和手機边臼,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評論 3 395
  • 文/潘曉璐 我一進店門哄尔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人柠并,你說我怎么就攤上這事岭接。” “怎么了臼予?”我有些...
    開封第一講書人閱讀 164,491評論 0 354
  • 文/不壞的土叔 我叫張陵鸣戴,是天一觀的道長。 經(jīng)常有香客問我粘拾,道長窄锅,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,636評論 1 293
  • 正文 為了忘掉前任缰雇,我火速辦了婚禮入偷,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘械哟。我一直安慰自己疏之,他們只是感情好,可當我...
    茶點故事閱讀 67,676評論 6 392
  • 文/花漫 我一把揭開白布暇咆。 她就那樣靜靜地躺著锋爪,像睡著了一般丙曙。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上几缭,一...
    開封第一講書人閱讀 51,541評論 1 305
  • 那天河泳,我揣著相機與錄音,去河邊找鬼年栓。 笑死拆挥,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的某抓。 我是一名探鬼主播纸兔,決...
    沈念sama閱讀 40,292評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼否副!你這毒婦竟也來了汉矿?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,211評論 0 276
  • 序言:老撾萬榮一對情侶失蹤备禀,失蹤者是張志新(化名)和其女友劉穎洲拇,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體曲尸,經(jīng)...
    沈念sama閱讀 45,655評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡赋续,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,846評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了另患。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片纽乱。...
    茶點故事閱讀 39,965評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖昆箕,靈堂內(nèi)的尸體忽然破棺而出鸦列,到底是詐尸還是另有隱情,我是刑警寧澤鹏倘,帶...
    沈念sama閱讀 35,684評論 5 347
  • 正文 年R本政府宣布薯嗤,位于F島的核電站,受9級特大地震影響纤泵,放射性物質(zhì)發(fā)生泄漏应民。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,295評論 3 329
  • 文/蒙蒙 一夕吻、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧繁仁,春花似錦涉馅、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春晤揣,著一層夾襖步出監(jiān)牢的瞬間桥爽,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評論 1 269
  • 我被黑心中介騙來泰國打工昧识, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留钠四,地道東北人。 一個月前我還...
    沈念sama閱讀 48,126評論 3 370
  • 正文 我出身青樓跪楞,卻偏偏與公主長得像缀去,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子甸祭,可洞房花燭夜當晚...
    茶點故事閱讀 44,914評論 2 355

推薦閱讀更多精彩內(nèi)容