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

Python中5種常見的反模式

開發(fā) 后端
Python 是2021年最流行的編程語言之一。簡單的語法使它成為很多程序員的入門首選。由于 Python 具有動態(tài)性和靈活性,有時候開發(fā)人員很容易編寫出錯誤及低效的代碼。

 本文將向大家介紹 Python 中常見的反模式,并給出了更好的編譯方法。

[[394520]]

1.對Iterable對象使用map()和filter()

內(nèi)置的 map 和 filter 可以幫助我們通過函數(shù)編程的原理在 Python 中轉(zhuǎn)換 iterable 對象。

這兩個方法都接受一個函數(shù)和一個 iterable 作為參數(shù),并返回相應(yīng)的對象。

通過將該對象作為參數(shù)傳遞到 Python 中的內(nèi)置列表構(gòu)造函數(shù),可以將其轉(zhuǎn)換為列表。

我們經(jīng)常使用 lambda 函數(shù)作為 map、filter 函數(shù)的參數(shù):

  1. my_list = [1, 2, 3, 4 ,5, 6, 7, 8, 9, 10] 
  2.  
  3. # 將每個元素乘以2 
  4. print(list(map(lambda x: x * 2, my_list)))  
  5. # [2, 4, 6, 8, 10, 12, 14, 16, 18, 20] 
  6.  
  7. # 過濾掉偶數(shù) 
  8. print(list(filter(lambda x: x % 2 == 0, my_list)))  
  9. # [2, 4, 6, 8, 10] 

上面的代碼看起來相當累贅和不清楚。使用列表理解可以實現(xiàn)相同結(jié)果:

  1. my_list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 
  2.  
  3. # 與map相同 
  4. print([x * 2 for x in my_list]) 
  5. # [2, 4, 6, 8, 10, 12, 14, 16, 18, 20] 
  6.  
  7. # 與filter相同 
  8. print([x for x in my_list if x % 2 == 0]) 
  9. # [2, 4, 6, 8, 10] 

不使用lambda函數(shù)后,列表理解變得更具可讀性和簡潔性。

2.輸入較大時使用列表理解

列表理解有助于我們編寫出清晰、簡潔的代碼。

但是,列表理解總是為 iterable 中的每個值創(chuàng)建一個列表。當輸入量非常大時,就會導(dǎo)致內(nèi)存占用過大的問題:我們的機器可能會崩潰。

生成器表達式結(jié)合了列表理解和生成器這兩個方面的優(yōu)點,為處理大型輸入序列提供了更有效的方法。

要創(chuàng)建生成器表達式,只需將列表中的 [] 方括號替換為()方括號。


生成器表達式并不是創(chuàng)建一個全新的列表,而是創(chuàng)建一個迭代器。

這會降低創(chuàng)建速度并優(yōu)化內(nèi)存分配。我們可以使用 next 函數(shù)或通過循環(huán)訪問生成器表達式的每個后續(xù)元素。

  1. my_list = [1, 2, 3, 4 ,5, 6, 7, 8, 9, 10] 
  2.  
  3. my_gen_expr = (x * 2 for x in my_list) 
  4.  
  5. print(next(my_gen_expr)) 
  6. print(next(my_gen_expr)) 
  7. # >> 
  8. # 2 
  9. # 4 
  10.  
  11. for x in my_gen_expr: 
  12.   print(x) 
  13. # >> 
  14. # 6 
  15. # 8 
  16. # 10 
  17. # 12 
  18. # 14 
  19. # 16 
  20. # 18 
  21. # 20 

注:生成器表達式是有狀態(tài)的,因此在重用時要注意。如果要多次使用迭代器,則可能需要重新創(chuàng)建迭代器。

3.不使用range()的情況

range 函數(shù)對迭代整數(shù)很有用。

  1. for i in range(10): 
  2.     print(i) 

當?shù)愃屏斜淼臄?shù)據(jù)結(jié)構(gòu)時,我們可以完全依賴for循環(huán)語法來訪問每個項目。代碼如下:

  1. my_list = [2, 4, 6, 8, 10] 
  2.  
  3. for item in my_list: 
  4.     print(item) 
  5.  
  6. # Output: 
  7. # 2 
  8. # 4 
  9. # 6 
  10. # 8 
  11. # 10 

但是,當想要訪問索引和元素時,我們可以使用列表長度下的 range 方法,如下所示:

  1. my_list = [2, 4, 6, 8, 10] 
  2.  
  3. for i in range(len(my_list)): 
  4.     print("index: ", i, "value: ", my_list[i]) 
  5.      
  6. Output
  7. index: 0 value: 2 
  8. index: 1 value: 4 
  9. index: 2 value: 6 
  10. index: 3 value: 8 
  11. index: 4 value: 10 

代碼看起來不可讀,因為我們必須在列表上調(diào)用 len,然后使用 range 方法包裝輸出。為了使代碼更加具有 python 風格,我們必須提高代碼的可讀性。

更好的方法是對 list 對象調(diào)用 enumerate 函數(shù)。這將創(chuàng)建一個生成器,生成列表項的索引和值。

  1. my_list = [2, 4, 6, 8, 10] 
  2.  
  3. for i, v in enumerate(my_list): 
  4.     print("index: ", i, "value: ", v) 
  5.      
  6. Output
  7. index: 0 value: 2 
  8. index: 1 value: 4 
  9. index: 2 value: 6 
  10. index: 3 value: 8 
  11. index: 4 value: 10 

代碼看起來是不是更加干凈了?

4.字典中鍵丟失的問題

字典具有快速訪問、分配、插入和刪除的能力,是一種非常流行的數(shù)據(jù)結(jié)構(gòu)。

但是新手開發(fā)人員訪問字典中不存在的密鑰時經(jīng)常會遇到問題。

  1. crypto_price = { 
  2.   "Bitcoin": 64000, 
  3.   "Ethereum": 2300, 
  4.   "Dogecoin": 0.12 
  5.  
  6. crypto_price["XRP"

處理該類問題的其中一種方法是檢查字典中是否存在密鑰,代碼如下:

  1. key = "XRP" 
  2.  
  3. if key not in crypto_price: 
  4.     crypto_price[key] = 1.2 
  5.      
  6. print(crypto_price[key]) 

另一種方法是使用 try/except 塊,如下所示:

  1. key = "XRP" 
  2.  
  3. try: 
  4.     xrp = crypto_price[key
  5. except raise KeyError: 
  6.     xrp = 1.2 
  7.      
  8. crypto_price[key] = xrp 

上面的代碼確實實現(xiàn)了我們的目標,但是我們可以通過使用字典方法 get 進一步改進。

通過使用 get 方法來獲取相應(yīng)鍵的值,而不是使用方括號 [] 來訪問字典的鍵。

另外,如果鍵不存在,get 方法將返回 None,而不是拋出 KeyError。如果缺少鍵而不是無鍵,還可以將參數(shù)傳遞給 get 方法以獲取默認值。

  1. key = "XRP" 
  2.  
  3. if crypto_price.get("XRP"is None: 
  4.   crypto_price["XRP"] = 1.2 
  1. ada = crypto_price.get("ADA", 0) 
  2.  
  3. # Prints 0 
  4. print(ada) 

5.惰性關(guān)鍵字和位置參數(shù)設(shè)計

Python函數(shù)能夠同時接受位置參數(shù)和關(guān)鍵字參數(shù)。

位置參數(shù)是不后跟等號(=)和默認值的名稱。

關(guān)鍵字參數(shù)后面跟一個等號和一個給出其默認值的表達式。

得益于這種設(shè)計,python函數(shù)的創(chuàng)建和重用非常靈活。

但是,定義函數(shù)時,錯誤的設(shè)計選擇可能會導(dǎo)致代碼中難以修復(fù)的錯誤。

我們以計算復(fù)利的函數(shù)為例:

  1. # 復(fù)利計算器年/月復(fù)利 
  2. def calculate_compound_interest(principal, rate, time_in_years, 
  3.                                 compounded_monthly, to_string): 
  4.   t = 1 
  5.   if compounded_monthly: 
  6.     t = 12 
  7.   amt = principal * (1 + rate/(t * 100)) ** (time_in_years * t) 
  8.   if to_string: 
  9.     return f"${amt - principal:.2f}" 
  10.  
  11.   return amt - principal 
  12.     
  13.    
  14.   calculate_compound_interest(100, 5, 2, FalseFalse
  15.   # 10.25 

調(diào)用函數(shù)時出現(xiàn)的一個問題是,兩個布爾參數(shù)(compounded_monthly 和結(jié)尾的 to_string)很容易相互混淆。這就會出現(xiàn)難以追蹤的問題。

我們可以通過如下方式更改函數(shù)定義來提高可讀性:

  1. # 復(fù)利計算器年/月復(fù)利 
  2. def calculate_compound_interest(principal, rate, time_in_years, 
  3.                                 compounded_monthly=False, to_string=False): 

通過將兩個布爾參數(shù)指定為關(guān)鍵字參數(shù),函數(shù)調(diào)用方可以顯式地指定要設(shè)置的布爾值,這些值將覆蓋默認值。

  1. calculate_compound_interest(100, 5, 2, compounded_monthly=True
  2. # 10.49413355583269 
  3.  
  4. calculate_compound_interest(100, 5, 2, to_string=True
  5. '$10.25' 

但是,這仍然會出現(xiàn)問題,主要原因是關(guān)鍵字參數(shù)是可選的,因為沒有任何強制調(diào)用方將這些作為關(guān)鍵字參數(shù)使用。

因此,我們?nèi)匀豢梢允褂门f方法調(diào)用該函數(shù):

  1. calculate_compound_interest(100, 5, 2, FalseFalse

解決該問題的方法是僅在定義函數(shù)時強制布爾參數(shù)為關(guān)鍵字:

  1. # 復(fù)利計算器年/月復(fù)利 
  2. def calculate_compound_interest(principal, rate, time_in_years, *, # Changed 
  3.                                 compounded_monthly=False, to_string=False): 

我們看到,*符號表示位置參數(shù)的結(jié)束和僅關(guān)鍵字參數(shù)的開始。

如果這樣調(diào)用:

  1. calculate_compound_interest(100, 5, 2, FalseFalse

將發(fā)生以下錯誤:

  1. --------------------------------------------------------------------------- 
  2. TypeError                                 Traceback (most recent call last
  3. <ipython-input-32-faf75d2ad121> in <module> 
  4. ----> 1 print(calculate_compound_interest(1000, 5, 2, False, False)) 
  5. TypeError: calculate_compound_interest() takes 3 positional arguments but 5 were given 

但是,關(guān)鍵字參數(shù)及其默認行為仍將保持不變,如下所示:

  1. alculate_compound_interest(100, 5, 2, compounded_monthly=True
  2. # 10.49413355583269 
  3.  
  4. calculate_compound_interest(100, 5, 2, to_string=True
  5. '$10.25' 

然而,仍然存在一個問題。

假設(shè)調(diào)用者決定對前三個必需參數(shù)(principal、rate、time in years)混合使用位置和關(guān)鍵字。

如果這三個參數(shù)的函數(shù)參數(shù)名稱發(fā)生更改,我們將看到Python解釋器。它會這樣說:

  1. # 復(fù)利計算器年/月復(fù)利 
  2. def calculate_compound_interest(p, r, t_in_y, *, # Changed 
  3.                                 compounded_monthly=False, to_string=False): 
  1. calculate_compound_interest(principal=1000, rate=5, time_in_years=2) 
  2.  
  3. calculate_compound_interest(1000, 5, time_in_years=2) 

將發(fā)生以下錯誤:

  1. --------------------------------------------------------------------------- 
  2. TypeError                                 Traceback (most recent call last
  3. <ipython-input-36-42e7ec842cd5> in <module> 
  4. ----> 1 calculate_compound_interest(principal=1000, rate=5, time_in_years=2) 
  5. TypeError: calculate_compound_interest() got an unexpected keyword argument 'principal' 
  6. --------------------------------------------------------------------------- 
  7. TypeError                                 Traceback (most recent call last
  8. <ipython-input-37-1bc57c40980f> in <module> 
  9. ----> 1 calculate_compound_interest(1000, 5, time_in_years=2) 
  10. TypeError: calculate_compound_interest() got an unexpected keyword argument 'time_in_years' 

因為我們沒有考慮調(diào)用方顯式地使用位置參數(shù),所以代碼中斷。

python3.8中引入了一個解決方案,我們可以使用/參數(shù)重新定義函數(shù),該參數(shù)指示僅位置參數(shù)的結(jié)束位置。代碼如下:

  1. # 復(fù)利計算器年/月復(fù)利 
  2. def calculate_compound_interest(p, r, t_in_y, /, *,  # 改變 
  3.                                 compounded_monthly=False, to_string=False): 

現(xiàn)在這樣調(diào)用函數(shù)就會產(chǎn)生正確的結(jié)果:

  1. calculate_compound_interest(100, 5, 2, compounded_monthly=True
  2. # 10.49413355583269 
  3.  
  4. calculate_compound_interest(100, 5, 2, to_string=True
  5. '$10.25' 

但是,如果我們這樣調(diào)用:

  1. calculate_compound_interest(p=1000, r=5, t_in_y=2) 

也會顯示相應(yīng)的錯誤:

  1. ---------------------------------------------------------------------------  
  2. TypeError                                 Traceback (most recent call last)  
  3. <ipython-input-21-883e876a7e8b> in <module>  
  4. ----> 1 calculate_compound_interest(p=1000, r=5, t_in_y=2)  
  5.       2  
  6. TypeError: calculate_compound_interest() got some positional-only arguments passed as keyword arguments: 'p, r, t_in_y'  

以上。

 

責任編輯:華軒 來源: 今日頭條
相關(guān)推薦

2014-07-30 10:08:13

Python反模式

2009-06-29 18:11:40

JSP設(shè)計模式

2020-09-14 08:30:44

Kubernetes容器

2023-12-22 14:27:30

2020-10-09 06:52:31

設(shè)計模式軟件

2010-10-13 15:33:38

MySQL日志

2010-09-06 09:26:07

PPP協(xié)議

2020-06-28 10:15:39

架構(gòu)模式軟件

2017-09-14 09:30:38

軟件架構(gòu)模式

2021-04-13 11:32:34

開源開源治理開源代碼項目

2015-10-10 11:23:17

Java常量反模式

2015-09-22 10:56:13

Java反模式

2010-06-18 09:19:39

UML面向?qū)ο蠼?/a>

2011-05-24 09:30:26

Findbugs

2022-11-03 15:36:44

事件響應(yīng)反模式系統(tǒng)

2020-09-11 10:36:24

設(shè)計模式代碼

2020-03-19 22:16:05

數(shù)據(jù)概率分布Python實現(xiàn)

2024-09-09 14:38:41

數(shù)據(jù)戰(zhàn)略數(shù)據(jù)驅(qū)動

2021-10-29 05:53:51

前端測試開發(fā)代碼

2012-02-02 09:21:39

編程
點贊
收藏

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