作者 
| Avi_Chawla
譯者 
| 王德朕
編程(不僅Python,也包括其它編程語言)最好的一點是,有多種方法來實現(xiàn)同一解決方案。

使用不同的方法來達到相同的結(jié)果(圖像由作者繪制)
由于下述原因,有些方法會比其他方法更好:
- 消耗更少的內(nèi)存
 - 運行效率
 - 較少的代碼
 - 更容易理解
 - 邏輯簡單
 
在這篇文章中,我將向你介紹20種場景,這些場景都會讓開發(fā)者不知不覺的陷入臃腫,丑陋,復(fù)雜的Python編碼陷阱中,從而限制發(fā)揮Python的潛力。
除此之外,我還會針對每個錯誤提供一個替代方案進行解決。
??點擊這里查看本文的代碼??
開始吧!
1 多次使用打印語句

新手寫法
如果你想打印多個變量,簡單的方式是為每個變量都使用 
print 語句。
a, b, c = 10, 5, 3  
print(a)  
print(b)  
print(c)

優(yōu)雅的寫法
根據(jù)經(jīng)驗,使用多個 
print 語句通常是編程人員(特別是新手)在 Python 中編碼時最常犯的錯誤,因為他們不知道使用 print 
語句,可以在一行代碼中打印多個變量,代碼如下:
a, b, c = 10, 5, 3  
print(a, b, c, sep = "\n")
上述 
sep 參數(shù)用于指定 print 語句輸出各個變量值(a,b,c)之間的分隔符。
注意:end 
參數(shù)用于設(shè)置 print 語句輸出內(nèi)容的結(jié)尾字符。
a, b, c = 10, 5, 3  
print(a, end = "\n---\n")  
print(b, end = "\n---\n")  
print(c)
上述代碼中,參數(shù) 
end=”\n---\n” 用于當(dāng)輸出一行后,輸出 ---,然后在輸出新一行字符。
?
2 使用FOR 循環(huán)打印相同的變量

新手寫法
如題所示,你的目標(biāo)是多次打印相同的變量,所以你會創(chuàng)建一個 
FOR 循環(huán)并迭代預(yù)期打印次數(shù),對嗎?我的意思是,這有什么問題嗎?
repeat = 10  
a = "ABC"  
for _ in range(repeat):  
print(a, end = "")

優(yōu)雅的寫法
雖然編寫一個FOR循環(huán)沒有壞處,并且一切正常,但是沒有必要編寫一個 
FOR 循環(huán)來多次打印同一變量。
repeat = 10  
a = "ABC"  
print(a*repeat)
3 創(chuàng)建獨立變量來跟蹤循環(huán)中的索引

新手的寫法
方法1:
為實現(xiàn)這一目標(biāo),一般需要定義一個新變量(idx)跟蹤索引值,并在迭代時對它遞增,代碼如下:
idx = 0  
char_list = ["a", "b", "c", "d", "e", "f"]  
for i in char_list:  
print("index =", idx, "value =", i, sep = " ")  
idx += 1
方法2:
如果不使用上述方法,人們還會創(chuàng)建一個 
range 迭代器來跟蹤索引,代碼如下:
char_list = ["a", "b", "c", "d", "e", "f"]  
for idx in range(len(char_list)):  
print("index =", idx, "value =", char_list[idx], sep = " ")  
idx += 1

優(yōu)雅的寫法
感謝設(shè)計了 
enumerate() 函數(shù)的開發(fā)人員,使用這種方法可以按照下述方式跟蹤索引(idx)和值(i)。
char_list = ["a", "b", "c", "d", "e", "f"]  
for idx, i in enumerate(char_list):  
print("index =", idx, "value =", i, sep = " ")
4 使用FOR循環(huán)將列表轉(zhuǎn)換為字符串

字符串的列表(圖像由作者繪制)

新手寫法
如下所示,使用 
FOR 循環(huán)每次收集一個元素
char_list = ["A", "B", "C", "D", "E"]  
final_str = ""  
for i in char_list:  
final_str += i  
print(final_str)

優(yōu)雅的寫法
將列表轉(zhuǎn)換為字符串的優(yōu)雅方法是使用 
join() 方法,如下所示:
char_list = ["A", "B", "C", "D", "E"]  
final_str = "".join(char_list)  
print(final_str)
上述代碼不僅可以避免編寫一些不必要的長代碼,而且與 
FOR 循環(huán)方法一樣直觀。
5 使用 FOR 循環(huán)從列表中刪除重復(fù)項

新手寫法

從列表中刪除重復(fù)項(圖像由作者繪制)
再次使用 
FOR 循環(huán),通過迭代列表并在新列表中存儲唯一的元素來實現(xiàn)。
char_list = ["A", "B", "A", "D", "C", "B", "E"]  
final_list = []  
for i in char_list:  
    if i not in final_list:  
       final_list.append(i)  
print(final_list)

優(yōu)雅的寫法
只需要一行 
Python 代碼就可以從列表中刪除重復(fù)內(nèi)容,如下所示:
char_list = ["A", "B", "A", "D", "C", "B", "E"]  
set(list(char_list))
上面的代碼返回一個集合,你可以將其轉(zhuǎn)換為列表:
char_list = ["A", "B", "A", "D", "C", "B", "E"]  
list(set(list(char_list)))
6 使用 FOR 循環(huán)在列表中檢索元素

新手寫法
如果你想知道某個元素是否存在于列表(或集合)中,并返回一個布爾值(如果存在則為 
True,否則為 False),新手實現(xiàn)如下所示:
char_list = ["A", "B", "A", "D", "C", "B", "E"]  
search_char = "D"  
found = False  
for i in char_list:  
    if i == search_char:  
        found = True  
        break  
  
print(found)
代碼有點多,是吧?

優(yōu)雅的寫法
通過關(guān)鍵字in 
可以使用一行代碼實現(xiàn)。
char_list = ["A", "B", "A", "D", "C", "B", "E"]  
search_char = "D"  
search_char in char_list
7 使用一個迭代變量在兩個相同大小的迭代對象上進行迭代

新手寫法
該形式與第3-4節(jié)中所做相同,也就是為索引定義一個特定變量,這種實現(xiàn)比較簡單,如下所示:
list1 = [1, 3, 6, 2, 5]  
list2 = [0, 4, 1, 9, 7]  
for idx in range(len(list1)):  
    print("value1 =", list1[idx], "value2 =", list2[idx], sep = " ")

優(yōu)雅的寫法
有經(jīng)驗的方法是使用 
zip() 函數(shù),該函數(shù)可以在兩個可迭代對象將對應(yīng)位置的值進行匹配。
list1 = [1, 3, 6, 2, 5]  
list2 = [0, 4, 1, 9, 7]  
  
for i, j in zip(list1, list2):  
    print("value1 =", i, "value2 =", j, sep = " ")
8 使用 FOR 循環(huán)反轉(zhuǎn)列表

逆向列表(圖像由作者繪制)

新手寫法
正如前文所示,我們可以在列表上進行反向迭代并將元素附加到新列表中,代碼如下:
input_list  = [1, 2, 3, 4, 5]  
output_list = []  
  
for idx in range(len(input_list), 0, -1):  
    output_list.append(input_list[idx-1])  
  
print(output_list)

優(yōu)雅的寫法
如果你了解 
Python 中的切片,那優(yōu)秀的解決方案只需要一行代碼。
input_list  = [1, 2, 3, 4, 5]  
  
output_list = input_list[::-1]  
print(output_list)
不需要 
FOR 循環(huán)!
9 使用 FOR 循環(huán)檢查回文結(jié)構(gòu)

新手寫法
在擴展了上述情況(#9--反轉(zhuǎn)列表)的思路之后,我們可以檢查回文列表結(jié)構(gòu)。
input_list  = [1, 2, 3, 2, 1]  
output_list = []  
  
for idx in range(len(input_list), 0, -1):  
    output_list.append(input_list[idx-1])  
  
print(output_list == input_list)

優(yōu)雅的寫法
正如前文討論的那樣,有經(jīng)驗的方式是使用切片,并將結(jié)果與原列表進行比較。
input_list  = [1, 2, 3, 2, 1]  
  
output_list = input_list[::-1]  
print(output_list == input_list)
10 使用 FOR 循環(huán)計算迭代對象中元素的出現(xiàn)次數(shù)

新手寫法
查找元素頻率的簡單方法是使用 
FOR 循環(huán)在列表迭代,然后統(tǒng)計元素出現(xiàn)的次數(shù)。
char_list = ["A", "B", "A", "D", "C", "B", "E"]  
search_char = "B"  
char_count = 0  
  
for i in char_list:  
    if search_char == i:  
        char_count += 1  
  
print(char_count)

優(yōu)雅的寫法
在這種情況下,避免編寫 
FOR 循環(huán)的有經(jīng)驗寫法是使用 count() 方法。
char_list = ["A", "B", "A", "D", "C", "B", "E"]  
char_list.count("A")
也可以對字符串變量使用 
count() 方法。
string = "ABADCBE"  
string.count("A")
11 使用 FOR 循環(huán)獲取字符串的子串

新手寫法
本次目標(biāo)是從 
start_index 位置開始,返回一個長度為 n_chars 的字符串子串。
新手解決這個問題的方法是使用 
FOR 循環(huán),如下所示:
input_str = "ABCDEFGHIJKL"  
start_index = 4  
n_chars = 5  
  
output_str = ""  
  
for i in range(n_chars):  
    output_str += input_str[i+start_index]  
  
print(output_str)

優(yōu)雅的寫法
使用切片,可以避免 
FOR 循環(huán)。
input_str = "ABCDEFGHIJKL"  
start_index = 4  
n_chars = 5  
  
output_str = input_str[start_index:start_index+n_chars]  
print(output_str)
12 定義長整數(shù)常量
假設(shè)你想聲明一個值為1021的整數(shù)變量。

新手寫法
x = 1000000000000000000000
理想情況下,人們會連續(xù)寫0,并在打字時進行計數(shù),但如果有人想引用這個代碼,他們數(shù)0難道不會很麻煩嗎?

優(yōu)雅的寫法
為了提高可讀性,可以用 
_(下劃線)分隔一組0,如下所示:
x = 1_000_000_000_000_000_000_000
但這仍然是一個麻煩,為什么數(shù) 
0?
如果數(shù)字可以表示為 
a^b 形式,那應(yīng)該使用 pow() 方法。

用IF變換字符串大小寫
給定一個字符串,目標(biāo)使大寫字母變成小寫,反之亦然。

新手寫法
簡單的方法是檢查每個元素的大小寫,然后對每個字符都進行轉(zhuǎn)換。
input_str = "AbCDeFGhIjkl"  
output_str = ""  
  
for i in input_str:  
  
    if i.islower():  
        output_str += i.upper()  
  
    elif i.isupper():  
        output_str += i.lower()  
      
    else:  
        output_str += i  
  
print(output_str)
輸出沒有問題,但為什么要這么做?

優(yōu)雅的寫法
使用 
 swapcase ()方法。
input_str = "AbCDeFGhIjkl"  
output_str = input_str.swapcase()  
  
print(output_str)
14 獲取兩個集合的并集

合并兩個集合(圖像由作者繪制)

新手寫法
遍歷這兩個集合,將元素添加到一個新的集合中。
set_a = {1, 2, 4, 8}  
set_b = {3, 8, 7, 1, 9}  
  
union_set = set()  
  
for i in set_a:  
    union_set.add(i)  
  
for i in set_b:  
    union_set.add(i)  
  
print(union_set)代碼太多了,不是嗎?讓我們把它精簡到一行。

優(yōu)雅的寫法
Python中的集合為兩個集合的合并提供了一個union() 
方法。
set_a = {1, 2, 4, 8}  
set_b = {3, 8, 7, 1, 9}  
  
union_set = set_a.union(set_b)  
print(union_set)更重要的是,你可以將其擴展到任意數(shù)量的輸入集合。
set_a = {1, 2, 4, 8}  
set_b = {3, 8, 7, 1, 9}  
set_c = {5, 9, 10, 3, 2}  
set_d = {7, 2, 13, 15, 0}  
  
union_set = set_a.union(set_b, set_c, set_d)  
print(union_set)這很酷吧?想象一下,要合并4個集合,需要編寫多少個 
FOR 循環(huán)?
15 獲取兩個集合的交集

新手寫法
與上面討論的合并情況類似,我們可以尋找兩個集合之間的共同元素,如下所示:
set_a = {1, 2, 4, 8}  
set_b = {3, 8, 7, 1, 9}  
  
intersection_set = set()  
  
for i in set_a:  
    if i in set_b:  
        intersection_set.add(i)  
  
print(intersection_set)
優(yōu)雅的寫法
你可以使用 
intersection() 方法實現(xiàn)同樣的功能:
set_a = {1, 2, 4, 8}  
set_b = {3, 8, 7, 1, 9}  
  
intersection_set = set_a.intersection(set_b)  
  
print(intersection_set)
16 在 IF 語句中寫多個條件
為了詳細說明這一點,假設(shè)你想實現(xiàn)如下邏輯。

函數(shù)將輸入映射到輸出(圖像由作者繪制)

新手寫法
可以使用多個 
OR 分隔條件實現(xiàn)上述邏輯。
a = 1  
if a == 1 or a == 2 or a==3:  
    a += 1  
elif a == 4 or a == 5 or a==6:  
    a += 5  
else:  
    a *= 2  
print(a)

優(yōu)雅的寫法
避免使用多個條件語句的方法是使用關(guān)鍵字 
in,代碼如下:
a = 1  
if a in (1, 2, 3):  
    a += 1  
elif a in (4, 5, 6):  
    a += 5  
else:  
    a *= 2  
print(a)
17 更改列表中所有元素的數(shù)據(jù)類型
給定一個表示整數(shù)的字符串列表,目標(biāo)修改數(shù)據(jù)類型將其轉(zhuǎn)換為整數(shù)列表。

新手寫法
使用 
FOR 循環(huán)和類型強制轉(zhuǎn)換對單個元素進行變更。

優(yōu)雅的寫法
聰明的做法是使用 
map() 函數(shù),如下所示:
input_list = ["7", "2", "13", "15", "0"]  
output_list = list(map(int, input_list))  
print(output_list)
map() 
函數(shù)接收的第一個參數(shù)是 function(int),第二個參數(shù)是可迭代對象(input_list)。
18 交換變量
給定兩個變量,目標(biāo)是對變量值進行交換。

新手寫法
大多數(shù)C/C++程序員在這里采取的方法是定義一個新的變量(temp),他們通常也會在Python中擴展這個方法。
a = "123"  
b = "abc"  
temp = a  
a = b  
b = temp  
print(a, b)

優(yōu)雅的寫法
幸運的是,Python 
允許在一個語句中進行多次賦值,從而避免了對臨時變量的需求。
a = "123"  
b = "abc"  
a, b = b, a  
print(a, b)
19 使用嵌套循環(huán)生成兩個列表的所有組合
給定兩個列表(a的長度為n,b 
的長度為 m),生成 (n*m)個組合。

新手寫法
編寫兩個嵌套的FOR循環(huán),并將所有組合追加到列表中。
list1 = ["A", "B", "C"]  
list2 = [1, 2]  
 
combinations = []  
for i in list1:  
    for j in list2:  
        combinations.append([i, j])  
print(combinations)

優(yōu)雅的寫法
優(yōu)雅的寫法是使用 
itertools 庫中的 product()方法,如下所示:
from itertools import product  
list1 = ["A", "B", "C"]  
list2 = [1, 2]  
combinations = list(product(list1, list2))  
print(combinations)
20 結(jié)論
在這篇文章中,我展示了20種不同場景,我相信大多數(shù)Python程序員都經(jīng)歷過這些情況,而且可能也采取了錯誤的編碼解決方案,如果你注意到,在大多數(shù)情況下,優(yōu)雅的寫法主要側(cè)重于避免使用 
FOR 循環(huán)進行編碼。
作為這篇文章的重點,你應(yīng)該永遠記住,在大多數(shù)情況下,你想出的第一個解決方案并不是最優(yōu)方案,因此,使用谷歌搜索總是有幫助的,這也是為什么不完美主義的思維方式,對一名講究的程序員非常重要的原因(不僅是Python,其它語言也一樣)。
原文鏈接:
??https://towardsdatascience.com/20-newbie-mistakes-that-even-skilled-python-programmers-make-6879048731a4??
譯者簡介
王德朕,51CTO社區(qū)編輯,10年互聯(lián)網(wǎng)產(chǎn)研經(jīng)驗,6年IT教培行業(yè)經(jīng)驗。