[Python] 程式結構與控制流

  • 2020 年 1 月 14 日
  • 筆記

1. 條件語句

if、else與elif語句用於控制條件程式碼的執行。條件語句的一般格式如下:

if expression:      statements  elif expression:      statements  elif expression:      statements  ...  else:      statements

如果不需要執行任何操作,可以省略條件語句的else和elif子句。如果特定子句下不存在要執行的語句,可以使用pass語句。

2. 循環與迭代

可以使用for和while語句實現循環,例如:

while expression:      statements    for i in s:      statements

while語句反覆執行循環體中的語句。直到相關表達式求值為false。for語句迭代s中的所有元素,直到再元可用元素。for語句僅適用於可支援迭代的對象。 如果迭代中使用的元素是元素大小完全一致的序列,每次迭代時,會把相應序列的各個元素賦值給變數x、y和z。儘管使用這行程式碼時s大多為元組序列,但s中的各項可以為任意類型的序列,包括列表、生成器和字元串。 循環時,除了數據值之外,有時還需要跟蹤數字索引,可以使用內置函數enumerate(),例如:

for i,x in enumerate(s):      statements

enumerate(s)創建了一個迭代器,其返回值就是一個元組的序列(0, s[0])、(1, s[1])、(2, s[2])等等。關於迭代的另一個常見問題是並行迭代兩個以上的序列,可以使用zip()函數,例如:

for x, y in zip(s, t):      statements

zip(s, t)將序列s和t組合成一個元組序列(s[0], t[0])、(s[1], t[1])、(s[2], t[2])等等。如果s和t的長度不等,則用完長度最短的索引為止。 使用break語句可從循環中跳出,例如:

for line in open("foo.txt"):      stripped = line.strip()      if not stripped:          break # 遇到空行,停止讀取

使用continue語句可以跳到循環的下一次迭代,例如:

for line in open("foo.txt"):      stripped = line.strip()      if not stripped:          continue # 跳過空行

3. 異常

異常會中斷程式的正常控制流。使用raise語句可以引發異常。raise語句的一般格式是raise Exception([value]),其中Exception是異常類型,而value是一個指定異常相關細節的可選值,例如:

raise RuntimeError("unrecoverable Error")

如果raise語句沒有帶任何參數,將會再次引發最近一次生成的異常。使用try和except語句可以捕捉異常,例如:

try:      f = open('foo')  except IOError as e:      statements

出現異常時,解釋器將停止執行try程式碼塊中的語句,並尋找可匹配該異常的except子句。執行完except子句後,控制權就會傳遞給出現在try-except程式碼塊之後的第一條語句。try-except語句可以嵌套使用。如果異常傳遞到程式的最頂級卻仍未被捕獲,解釋器就會終止程式運行。 except語句的可選修飾符as var提供了一個變數名稱,如果出現異常,就會在其中放置一個提供給raise語句的異常類型的實例。異常處理程式可以檢查該值,也可以使用isinstance()函數檢查異常類型。 處理程式可以捕獲多種類型的異常,使用Exception可以捕獲除與程式退出相關之外的所有異常,例如:

try:      do something  except (IOError, TypeError) as e:      # 處理I/O、類型異常  except Exception as e:      # 處理所有異常

使用except語句時如果不帶任何異常類型,也會捕獲所有異常,例如:

try:      do something  except:      # 處理所有異常

try語句也支援else子句,它必須跟在最後一個except子句後面。如果try程式碼塊中的程式碼沒有引發異常,就會執行else子句中的程式碼,例如:

try:      f = open('foo', 'r')  except IOError as e:      # 處理I/O異常  else:      data = f.read()      f.close()

finally語句為try程式碼塊中的程式碼定義了結束操作,例如:

f = open('foo', 'r')  try:      # do something  finally:      f.close()

finally用於提供一些程式碼,無論是否出現錯誤,都必須執行該程式碼。如果沒有引發異常,finally子句中的程式碼將在try程式碼塊中的程式碼執行完畢後立即執行。如果引發了異常,控制權首先傳遞給finally子句的第一條語句。這段程式碼執行完畢後,將交由另一個異常處理程式進行處理。 如果要創建新異常,就定義父類為Exception的新類,例如:

class NetworkError(Exception):      pass

可用如下方式使用這個異常:

raise NetworkError("Cannot find host.")

引發異常時,將提供給raise語句的可選值用作異常的類構造函數的參數。通常它就是一個表示消息的字元串,但用戶自定義的異常可以帶有一個或多個異常值,例如:

class DeviceError(Exception):      def __init__(self,errno,msg):          self.args = (errno,msg)          self.errno = errno          self.errmsg = msg  raise DeviceError(1, 'Not Responding')

包含__init__()方法參數的元組賦值給屬性self.args。列印異常跟蹤消息時就需要用到這個屬性。如果不定義該屬性,出現錯誤時,用戶就無法看到關於異常的有用資訊。

4. 上下文管理與with語句

with語句支援在由上下文管理器對象控制的運行時上下文中執行一系列語句,例如:

with open("debuglog", "a") as f:      f.write("Debuggingn")      statements      f.write("Donen")    import threading  lock = threading.Lock()  with lock:      statements

在第一小段程式碼中,當控制流離開with語句後面的程式碼塊時,with語句將自動關閉已打開的文件。在第二小段程式碼中,當控制流進入with語句後面的程式碼塊時自動請求一個鎖定,而在控制流離開時又自動釋放了這個鎖定。 with obj語句在控制流進入和離開其後的相關程式碼塊時,允許對象obj管理所發生的事情。執行with obj語句時,它執行方法obj.__enter__()來指示正在進入一個新的上下文。當控制流離開該上下文時,就會執行方法obj.__exit__(type, value, traceback)。如果沒有引發異常,__exit__()方法的3個參數均被設為None。否則,它們將包含與導致控制流離開上下文的異常相關的類型、值和跟蹤資訊。__exit__()方法返回True或False,分別指示被引發的異常得到了還是沒有得到處理。 with obj語句接受一個可選的as var說明符,如果指定了該說明符,obj.__enter__()方法的返回值將保存在var中。with語句只對支援上下文管理協議(__enter__()和__exit__()方法)的對象有效。用戶定義的類可以實現這些方法,從而定義它們自己的自定義上下文管理。例如:

class ListTransaction(object):      def __init__(self, thelist):          self.thelist = thelist      def __enter__(self):          self.workingcopy = list(self.thelist)          return self.workingcopy      def __exit__(self, type, value, tb):          if type is None:              self.thelist[:] = self.workingcopy          return False

5. 斷言與__debug__

assert語句可以在程式中引入調試程式碼。assert的一般格式為:

    assert test [, msg]

其中test是一個表達式,其值應該為True或False。如果test求值為False,assert就會引發AssertionError異常並使用在assert中提供的可選消息msg,例如:

    def write_date(file, data):          assert file, "write_data: file not defined"

除了assert語句之外,Python還提供內置的只讀變數__debug__,除非解釋器運行在最優模式中,不則它的值為True。程式可以在需要時檢查這個變數。