自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Python 3000字編程風(fēng)格指南

開發(fā) 后端
今天討論 Python 編程風(fēng)格,如何寫出更加Pythonic的代碼是本篇討論的話題。就Python語言,推薦使用EAFP風(fēng)格,個別受保護(hù)的塊,若無法實現(xiàn)原子操作的地方可以使用LBYL風(fēng)格。

今天討論 Python 編程風(fēng)格,如何寫出更加Pythonic的代碼是本篇討論的話題。

基本目錄結(jié)構(gòu):

  • 1 基本編程習(xí)慣
  • 1.1 多余的空格
  • 1.2 是否為 None 判斷
  • 1.3 lamda 表達(dá)式
  • 1.4 最小化受保護(hù)代碼
  • 1.5 保持邏輯完整性
  • 1.6 使用語義更加明確的方法
  • 2 EAFP 防御編程風(fēng)格
  • 3 LBYL 防御編程風(fēng)格
  • 3.1 程序每次運(yùn)行都要檢查
  • 3.2 很難一次考慮所有可能異常
  • 3.3 代碼的可讀性下降

1 基本編程習(xí)慣

Python代碼的編程習(xí)慣主要參考PEP8:

https://www.python.org/dev/peps/pep-0008/

里面主要包括如每行代碼長度不超過80,函數(shù)間空一行等。同時,我們可以使用一些好用的小工具輔助我們寫出更加符合習(xí)慣的Python代碼,如flake8等小插件。

結(jié)合以上這些參考資料和工具,我們這篇專題總結(jié)就不會過多去講語法相關(guān)的格式化。而是更多精力放在一些典型的、常用的對比分析上,告訴大家常用的代碼書寫習(xí)慣,哪些寫法不夠符合習(xí)慣等。

[[334101]]

1.1 多余的空格

以下函數(shù)賦值符合習(xí)慣:

  1. foo(a, b=0, {'a':1,'b':2}, (10,)) 

但是,下面出現(xiàn)的多余空格都不符合習(xí)慣:

  1. # 這些空格都是多余的 
  2. foo ( a, b = 0, { 'a':1, 'b':2 }, (10, )) 

下面代碼,有空格又更符合習(xí)慣:

  1. i += 1 
  2. num = num**2 + 1 
  3. def foo(nums: List) 

尤其容易忽略的一個空格,增加函數(shù)元信息時要有一個空格:

  1. def foo(nums: list): # 此處根據(jù)官方建議nums: list間要留有一個空格 
  2. pass 

1.2 是否為 None 判斷

判斷某個對象是否為None,下面符合習(xí)慣:

  1. if arr is None: 
  2. pass 
  3.  
  4. if arr is not None: 
  5. pass 

下面寫法不符合習(xí)慣,一般很少見:

  1. if arr == None: 
  2. pass 

特別的,對于list,tuple,set,dict,str等對象,使用下面方法判斷是否為None更加符合習(xí)慣:

  1. if not arr: #為 None 時,滿足條件 
  2. pass 
  3.  
  4. if arr: # 不為 None 時,滿足條件 
  5. pass 

1.3 lamda 表達(dá)式

lambda 表達(dá)式適合一些key參數(shù)賦值等,一般不習(xí)慣這么寫:

  1. f = lambda i: i&1 

下面寫法更加符合習(xí)慣:

  1. def is_odd(i): return i&1 

1.4 最小化受保護(hù)代碼

要想代碼更健壯,我們一般都做防御性的工作,最小化受保護(hù)的代碼更加符合習(xí)慣,如下為了防御鍵不存在問題,加一個try:

  1. try: 
  2. val = d['c'
  3. except KeyError: 
  4. print('c' not existence) 

上面寫法是合理的,但是下面代碼在捕獲KeyError時,又嵌套一個函數(shù)是不符合習(xí)慣的:

  1. try: 
  2. val = foo(d['c']) # 這樣寫也會捕獲foo函數(shù)中的KeyError異常 
  3. except KeyError: 
  4. print('c' not existence) 

這樣寫也會捕獲foo函數(shù)中的KeyError異常,不符合習(xí)慣。

1.5 保持邏輯完整性

根據(jù)官方指南,只有if邏輯return,而忽視可能的x為負(fù)時的else邏輯,不可?。?/p>

  1. def foo(x): 
  2. if x >= 0: 
  3. return math.sqrt(x) 

建議寫法:

  1. def foo(x): 
  2. if x >= 0: 
  3. return math.sqrt(x) 
  4. else
  5. return None 

或者這樣寫:

  1. def foo(x): 
  2. if x < 0: 
  3. return None 
  4. return math.sqrt(x) 

所以,不要為了刻意追求代碼行數(shù)最少,而忽視使用習(xí)慣。

1.6 使用語義更加明確的方法

判斷字符串是否以ize結(jié)尾時,不建議這樣寫:

  1. if s[-3:] == 'ize'
  2. print('ends ize'

使用字符串的endswith方法判斷是否以什么字符串結(jié)尾,顯然可讀性更好:

  1. if s.endswith('ize'): 
  2. print('ends ize'

以上這些只要平時多加注意,理解起來不是問題。其實除了PEP8指定的這些代碼編寫習(xí)慣外,還有一種與代碼健壯性息息相關(guān)的編程風(fēng)格,今天重點介紹這方面的編程習(xí)慣。

2 EAFP 防御編程風(fēng)格

為了提升代碼的健壯性,我們要做防御性編程,Python中的try和except就是主要用來做這個:

  1. d = {'a': 1, 'b': [1, 2, 3]} 
  2.  
  3. try: 
  4. val = d['c'
  5. except KeyError: 
  6. print('key not existence'

try塊中代碼是受保護(hù)的,如果鍵不存在,except捕獲到KeyError異常,并處理這個異常信息。

而下面的代碼,一旦從字典中獲取不存在的鍵,如果沒有任何try保護(hù),則程序直接中斷在這里,表現(xiàn)出來的現(xiàn)象就是app直接掛掉或閃退,這顯然非常不友好。

  1. d = {'a': 1, 'b': [1, 2, 3]} 
  2. val = d['c'

再舉一個try和except使用的例子,如果目錄已存在則觸發(fā)OSError異常,并通過except捕獲到然后在塊里面做一些異常處理邏輯。

  1. import os 
  2. try: 
  3. os.makedirs(path) 
  4. except OSError as exception: 
  5. if exception.errno != errno.EEXIST: 
  6. raise # PermissionError 等異常 
  7. else
  8. # path 目錄已存在 

以上這種使用try和except的防御性編程風(fēng)格,在Python中有一個比較抽象的名字:EAFP

它的全稱為:

  • Easier to Ask for Forgiveness than Permission.

沒必要糾結(jié)上面這句話的哲學(xué)含義。

知道在編程方面的指代意義就行:首先相信程序會正確執(zhí)行,然后如果出錯了我們再處理錯誤。

使用try和except這種防御風(fēng)格,優(yōu)點明顯,try里只寫我們的業(yè)務(wù)邏輯,except里寫異常處理邏輯,幾乎無多余代碼,Python指南里也提倡使用這種風(fēng)格。

但是任何事物都有兩面性,這種寫法也不例外。那么,EAFP防御風(fēng)格有何問題呢?它主要會帶來一些我們不想出現(xiàn)的副作用。

舉一個例子,如下try塊里的邏輯:出現(xiàn)某種情況修改磁盤的csv文件里的某個值,這些邏輯都順利完成,但是走到下面這句代碼時程序出現(xiàn)異常,進(jìn)而被except捕獲,然后做一些異常處理:

  1. try: 
  2. if condition: 
  3. revise_csv # 已經(jīng)污染csv文件 
  4.  
  5. do_something # 觸發(fā)異常 
  6. except Exception: 
  7. handle_exception 

由于try塊里的邏輯分為兩步執(zhí)行,它們不是一個原子操作,所以首先修改了csv文件,但是do_something卻出現(xiàn)異常,導(dǎo)致污染csv文件。

其實,除了以上EAFP防御性編程風(fēng)格外,還有一種編程風(fēng)格與它截然不同,它雖然能很好的解決EAFP的副作用,但是缺點更加明顯,所以Python中不太提倡大量的使用此種風(fēng)格。

3 LBYL 防御編程風(fēng)格

再介紹另一種編程風(fēng)格:LBYL

它的特點:指在執(zhí)行正常的業(yè)務(wù)邏輯前做好各種可能出錯檢查,需要寫一個又一個的if和else邏輯。

如EAFP風(fēng)格的代碼:

  1. d = {'a': 1, 'b': [1, 2, 3]} 
  2.  
  3. try: 
  4. val = d['c'
  5. except KeyError: 
  6. print('key not existence'

使用LBYL來寫就是如下這樣:

  1. if 'c' in d: 
  2. val = d['c'
  3. else
  4. print('key not existence'

EAFP風(fēng)格的代碼如下:

  1. import os 
  2. try: 
  3. os.makedirs(path) 
  4. except OSError as exception: 
  5. if exception.errno != errno.EEXIST: 
  6. raise # PermissionError 等異常 
  7. else
  8. # path 目錄已存在 

使用LBYL來寫就是如下這樣:

  1. import os 
  2.  
  3. if not os.path.isdir(path): 
  4. print('不是一個合法路徑'
  5.  
  6. else
  7. if not os.path.exists(path): 
  8. os.makedirs(path) 
  9. else
  10. print('路徑已存在'

通過以上兩個例子,大家可以看出LBYL風(fēng)格和EAFP風(fēng)格迥異。

LBYL的代碼if和else較多,這種風(fēng)格會有以下缺點。

3.1 程序每次運(yùn)行都要檢查

程序每次運(yùn)行都要檢查,不管程序是不是真的會觸發(fā)這些異常。

  1. if 'c' in d: # 每次必做檢查 
  2. val = d['c'
  3.  
  4. if not os.path.isdir(path): # 每次必做檢查 
  5. print('不是一個合法路徑'
  6.  
  7. else
  8. if not os.path.exists(path): # 每次必做檢查 
  9. os.makedirs(path) 
  10. else
  11. print('路徑已存在'

3.2 很難一次考慮所有可能異常

很難一次性考慮到所有可能的異常,更讓人頭疼的事情是,一旦遺漏某些異常情況,錯誤經(jīng)常不在出現(xiàn)的地方,而在很外層的一個調(diào)用處。這就會導(dǎo)致我們花很多時間調(diào)試才能找到最終出錯的地方。

  1. def f1 
  2. if con1: 
  3. # do1 
  4. if con2: 
  5. # do2 
  6. # 但是遺漏了情況3,未在f1函數(shù)中報異常 

3.3 代碼的可讀性下降

要寫很多與主邏輯無關(guān)的if-else,程序真正的邏輯就變得難以閱讀。最后導(dǎo)致我們很難看出這個只是判斷,還是程序邏輯/業(yè)務(wù)的判斷。但是,如果用try-catch,那么try代碼塊里面可以只寫程序的邏輯,在except里面處理所有的異常。

結(jié)論:就Python語言,推薦使用EAFP風(fēng)格,個別受保護(hù)的塊,若無法實現(xiàn)原子操作的地方可以使用LBYL風(fēng)格。

 

責(zé)任編輯:未麗燕 來源: 今日頭條
相關(guān)推薦

2017-02-13 13:14:07

2017-01-12 14:55:50

JavaScript編程

2015-09-22 10:04:38

GoogleJava編程

2023-12-04 09:00:00

PythonRuff

2021-05-06 11:04:55

GooglePython代碼

2010-09-14 14:28:58

Scala

2024-10-08 05:00:00

PEP 8編碼Python

2020-10-29 15:15:09

SQL數(shù)據(jù)清洗Python

2013-07-10 11:32:57

編碼風(fēng)格

2023-12-11 15:32:30

面向?qū)ο缶幊?/a>OOPpython

2022-12-05 09:32:29

Go 語言風(fēng)格規(guī)范

2012-03-22 17:16:24

Java

2023-08-14 14:04:14

JavaScript函數(shù)式編程

2010-11-17 11:31:22

Scala基礎(chǔ)面向?qū)ο?/a>Scala

2022-05-26 07:42:22

Python編輯器VSCode

2024-06-19 08:49:48

2021-05-28 05:34:06

Golang語言編程

2010-07-20 13:32:25

Perl編程格式

2011-12-12 11:16:02

iOS并發(fā)編程

2011-07-03 10:16:45

Core Animat
點贊
收藏

51CTO技術(shù)棧公眾號