最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

對Python新手編程過程中如何規(guī)避一些常見問題的建議

 更新時間:2015年04月01日 16:16:09   作者:Constantine Lignos  
這篇文章中作者對Python新手編程過程中如何規(guī)避一些常見問題給出了建議,主要著眼于初學(xué)者對于一些常用函數(shù)方法在平時的使用習(xí)慣中的問題給出建議,需要的朋友可以參考下

這篇文章收集了我在Python新手開發(fā)者寫的代碼中所見到的不規(guī)范但偶爾又很微妙的問題。本文的目的是為了幫助那些新手開發(fā)者渡過寫出丑陋的Python代碼的階段。為了照顧目標(biāo)讀者,本文做了一些簡化(例如:在討論迭代器的時候忽略了生成器和強(qiáng)大的迭代工具itertools)。

對于那些新手開發(fā)者,總有一些使用反模式的理由,我已經(jīng)嘗試在可能的地方給出了這些理由。但通常這些反模式會造成代碼缺乏可讀性、更容易出bug且不符合Python的代碼風(fēng)格。如果你想要尋找更多的相關(guān)介紹資料,我極力推薦The Python TutorialDive into Python。
迭代

range的使用

Python編程新手喜歡使用range來實現(xiàn)簡單的迭代,在迭代器的長度范圍內(nèi)來獲取迭代器中的每一個元素:

for i in range(len(alist)):
  print alist[i]

應(yīng)該牢記:range并不是為了實現(xiàn)序列簡單的迭代。相比那些用數(shù)字定義的for循環(huán),雖然用range實現(xiàn)的for循環(huán)顯得很自然,但是用在序列的迭代上卻容易出bug,而且不如直接構(gòu)造迭代器看上去清晰:
 

for item in alist:
  print item

range的濫用容易造成意外的大小差一(off-by-one)錯誤,這通常是由于編程新手忘記了range生成的對象包括range的第一個參數(shù)而不包括第二個,類似于java中的substring和其他眾多這種類型的函數(shù)。那些認(rèn)為沒有超出序列結(jié)尾的編程新手將會制造出bug:
 

# 迭代整個序列錯誤的方法
alist = ['her', 'name', 'is', 'rio']
for i in range(0, len(alist) - 1): # 大小差一(Off by one)!
  print i, alist[i]

不恰當(dāng)?shù)厥褂胷ange的常見理由:
1. 需要在循環(huán)中使用索引。這并不是一個合理的理由,可以用以下方式代替使用索引:
 

for index, value in enumerate(alist):
  print index, value

2. 需要同時迭代兩個循環(huán),用同一個索引來獲取兩個值。這種情況下,可以用zip來實現(xiàn):
 

for word, number in zip(words, numbers):
  print word, number

3. 需要迭代序列的一部分。在這種情況下,僅需要迭代序列切片就可以實現(xiàn),注意添加必要的注釋注明用意:
 

for word in words[1:]: # 不包括第一個元素
  print word

有一個例外:當(dāng)你迭代一個很大的序列時,切片操作引起的開銷就比較大。如果序列只有10個元素,就沒有什么問題;但是如果有1000萬個元素時,或者在一個性能敏感的內(nèi)循環(huán)中進(jìn)行切片操作時,開銷就變得非常重要了。這種情況下可以考慮使用xrange代替range [1]。

在用來迭代序列之外,range的一個重要用法是當(dāng)你真正想要生成一個數(shù)字序列而不是用來生成索引:
 

# Print foo(x) for 0<=x<5
for x in range(5):
  print foo(x)

正確使用列表解析

如果你有像這樣的一個循環(huán):
 

# An ugly, slow way to build a list
words = ['her', 'name', 'is', 'rio']
alist = []
for word in words:
  alist.append(foo(word))

你可以使用列表解析來重寫:
 

words = ['her', 'name', 'is', 'rio']
alist = [foo(word) for word in words]

為什么要這么做?一方面你避免了正確初始化列表可能帶來的錯誤,另一方面,這樣寫代碼讓看起來很干凈,整潔。對于那些有函數(shù)式編程背景的人來說,使用map函數(shù)可能感覺更熟悉,但是在我看來這種做法不太Python化。

其他的一些不使用列表解析的常見理由:

1. 需要循環(huán)嵌套。這個時候你可以嵌套整個列表解析,或者在列表解析中多行使用循環(huán):
 

words = ['her', 'name', 'is', 'rio']
letters = []
for word in words:
  for letter in word:
    letters.append(letter)

使用列表解析:
 

words = ['her', 'name', 'is', 'rio']
letters = [letter for word in words
         for letter in word]

注意:在有多個循環(huán)的列表解析中,循環(huán)有同樣的順序就像你并沒有使用列表解析一樣。

2. 你在循環(huán)內(nèi)部需要一個條件判斷。你只需要把這個條件判斷添加到列表解析中去:
 

words = ['her', 'name', 'is', 'rio', '1', '2', '3']
alpha_words = [word for word in words if isalpha(word)]

一個不使用列表解析的合理的理由是你在列表解析里不能使用異常處理。如果迭代中一些元素可能引起異常,你需要在列表解析中通過函數(shù)調(diào)用轉(zhuǎn)移可能的異常處理,或者干脆不使用列表解析。
性能缺陷

在線性時間內(nèi)檢查內(nèi)容

在語法上,檢查list或者set/dict中是否包含某個元素表面上看起來沒什么區(qū)別,但是表面之下卻是截然不同的。如果你需要重復(fù)檢查某個數(shù)據(jù)結(jié)構(gòu)里是否包含某個元素,最好使用set來代替list。(如果你想把一個值和要檢查的元素聯(lián)系起來,可以使用dict;這樣同樣可以實現(xiàn)常數(shù)檢查時間。)

# 假設(shè)以list開始
lyrics_list = ['her', 'name', 'is', 'rio']
 
# 避免下面的寫法
words = make_wordlist() # 假設(shè)返回許多要測試的單詞
for word in words:
  if word in lyrics_list: # 線性檢查時間
    print word, "is in the lyrics"
 
# 最好這么寫
lyrics_set = set(lyrics_list) # 線性時間創(chuàng)建set
words = make_wordlist() # 假設(shè)返回許多要測試的單詞
for word in words:
  if word in lyrics_set: # 常數(shù)檢查時間
    print word, "is in the lyrics"

[譯者注:Python中set的元素和dict的鍵值是可哈希的,因此查找起來時間復(fù)雜度為O(1)。

應(yīng)該記?。簞?chuàng)建set引入的是一次性開銷,創(chuàng)建過程將花費(fèi)線性時間即使成員檢查花費(fèi)常數(shù)時間。因此如果你需要在循環(huán)里檢查成員,最好先花時間創(chuàng)建set,因為你只需要創(chuàng)建一次。
變量泄露

循環(huán)

通常說來,在Python中,一個變量的作用域比你在其他語言里期望的要寬。例如:在Java中下面的代碼將不能通過編譯:
 

// Get the index of the lowest-indexed item in the array
// that is > maxValue
for(int i = 0; i < y.length; i++) {
  if (y[i] > maxValue) {
    break;
  }
}
// i在這里出現(xiàn)不合法:不存在i
processArray(y, i);

然而在Python中,同樣的代碼總會順利執(zhí)行且得到意料中的結(jié)果:
 

for idx, value in enumerate(y):
  if value > max_value:
    break
 
processList(y, idx)

這段代碼將會正常運(yùn)行,除非子y為空的情況下,此時,循環(huán)永遠(yuǎn)不會執(zhí)行,而且processList函數(shù)的調(diào)用將會拋出NameError異常,因為idx沒有定義。如果你使用Pylint代碼檢查工具,將會警告:使用可能沒有定義的變量idx。

解決辦法永遠(yuǎn)是顯然的,可以在循環(huán)之前設(shè)置idx為一些特殊的值,這樣你就知道如果循環(huán)永遠(yuǎn)沒有執(zhí)行的時候你將要尋找什么。這種模式叫做哨兵模式。那么什么值可以用來作為哨兵呢?在C語言時代或者更早,當(dāng)int統(tǒng)治編程世界的時候,對于需要返回一個期望的錯誤結(jié)果的函數(shù)來說為通用的模式為返回-1。例如,當(dāng)你想要返回列表中某一元素的索引值:
 

def find_item(item, alist):
  # None比-1更加Python化
  result = -1
  for idx, other_item in enumerate(alist):
    if other_item == item:
      result = idx
      break
 
  return result

通常情況下,在Python里None是一個比較好的哨兵值,即使它不是一貫地被Python標(biāo)準(zhǔn)類型使用(例如:str.find [2])

外作用域

Python程序員新手經(jīng)常喜歡把所有東西放到所謂的外作用域——python文件中不被代碼塊(例如函數(shù)或者類)包含的部分。外作用域相當(dāng)于全局命名空間;為了這部分的討論,你應(yīng)該假設(shè)全局作用域的內(nèi)容在單個Python文件的任何地方都是可以訪問的。

對于定義整個模塊都需要去訪問的在文件頂部聲明的常量,外作用域顯得非常強(qiáng)大。給外作用域中的任何變量使用有特色的名字是明智的做法,例如,使用IN_ALL_CAPS 這個常量名。 這將不容易造成如下bug:
 

import sys
 
# See the bug in the function declaration?
def print_file(filenam):
  """Print every line of a file."""
  with open(filename) as input_file:
    for line in input_file:
      print line.strip()
 
if __name__ == "__main__":
  filename = sys.argv[1]
  print_file(filename)

如果你看的近一點(diǎn),你將看到print_file函數(shù)的定義中用filenam命名參數(shù)名,但是函數(shù)體卻引用的卻是filename。然而,這個程序仍然可以運(yùn)行得很好。為什么呢?在print_file函數(shù)里,當(dāng)一個局部變量filename沒有被找到時,下一步是在全局作用域中去尋找。由于print_file的調(diào)用在外作用域中(即使有縮進(jìn)),這里聲明的filename對于print_file函數(shù)是可見的。

那么如何避免這樣的錯誤呢?首先,在外作用域中不是IN_ALL_CAPS這樣的全局變量就不要設(shè)置任何值[3]。參數(shù)解析最好交給main函數(shù),因此函數(shù)中任何內(nèi)部變量不在外作用域中存活。

這也提醒人們關(guān)注全局關(guān)鍵字global。如果你只是讀取全局變量的值,你就不需要全局關(guān)鍵字global。你只有在想要改變?nèi)肿兞棵玫膶ο髸r有使用global關(guān)鍵字的必要。你可以在這里獲取更多相關(guān)信息this discussion of the global keyword on Stack Overflow。
代碼風(fēng)格

向PEP8致敬

PEP 8是Python代碼的通用風(fēng)格指南,你應(yīng)該牢記在心并且盡可能去遵循它,盡管一些人有充分的理由不同意其中一些細(xì)小的風(fēng)格,例如縮進(jìn)的空格個數(shù)或使用空行。如果你不遵循PEP8,你應(yīng)該有除“我只是不喜歡那樣的風(fēng)格”之外更好的理由。下邊的風(fēng)格指南都是從PEP8中摘取的,似乎是編程者經(jīng)常需要牢記的。

測試是否為空

如果你要檢查一個容器類型(例如:列表,詞典,集合)是否為空,只需要簡單測試它而不是使用類似檢查len(x)>0這樣的方法:
 

numbers = [-1, -2, -3]
# This will be empty
positive_numbers = [num for num in numbers if num > 0]
if positive_numbers:
  # Do something awesome

如果你想在其他地方保存positive_numbers是否為空的結(jié)果,可以使用bool(positive_number)作為結(jié)果保存;bool用來判斷if條件判斷語句的真值。

測試是否為None

如前面所提到,None可以作為一個很好的哨兵值。那么如何檢查它呢?

如果你明確的想要測試None,而不只是測試其他一些值為False的項(如空容器或者0),可以使用:
 

if x is not None:
  # Do something with x

如果你使用None作為哨兵,這也是Python風(fēng)格所期望的模式,例如在你想要區(qū)分None和0的時候。

如果你只是測試變量是否為一些有用的值,一個簡單的if模式通常就夠用了:
 

if x:
  # Do something with x

例如:如果期望x是一個容器類型,但是x可能作另一個函數(shù)的返回結(jié)果值變?yōu)镹one,你應(yīng)該立即考慮到這種情況。你需要留意是否改變了傳給x的值,否則可能你認(rèn)為True或0. 0是個有用的值,程序卻不會按照你想要的方式執(zhí)行。

譯者注:

[1] 在Python2.x 中 range生成的是list對象,xrange生成的則是range對象;Python 3.x 廢除了xrange,range生成的統(tǒng)一為range對象,用list工廠函數(shù)可以顯式生成list;
[2] string.find(str)返回str在string中開始的索引值,如果不存在則返回-1;
[3] 在外作用于中不要給函數(shù)中的局部變量名設(shè)置任何值,以防止函數(shù)內(nèi)部調(diào)用局部變量時發(fā)生錯誤而調(diào)用外部作用域中的同名變量。

相關(guān)文章

  • python spilt()分隔字符串的實現(xiàn)示例

    python spilt()分隔字符串的實現(xiàn)示例

    split() 方法可以實現(xiàn)將一個字符串按照指定的分隔符切分成多個子串,本文介紹了spilt的具體使用,感興趣的可以了解一下
    2021-05-05
  • Python?SDK實現(xiàn)私服上傳下載的示例

    Python?SDK實現(xiàn)私服上傳下載的示例

    本文主要介紹了Python?SDK實現(xiàn)私服上傳下載的示例,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下<BR>
    2021-11-11
  • python實現(xiàn)網(wǎng)絡(luò)五子棋

    python實現(xiàn)網(wǎng)絡(luò)五子棋

    這篇文章主要為大家詳細(xì)介紹了python實現(xiàn)網(wǎng)絡(luò)五子棋,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-04-04
  • python3下載抖音視頻的完整代碼

    python3下載抖音視頻的完整代碼

    本文通過實例代碼給大家介紹了python3下載抖音視頻的相關(guān)知識,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-06-06
  • 解決python3 安裝不了PIL的問題

    解決python3 安裝不了PIL的問題

    今天小編就為大家分享一篇解決python3 安裝不了PIL的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-08-08
  • Python模仿POST提交HTTP數(shù)據(jù)及使用Cookie值的方法

    Python模仿POST提交HTTP數(shù)據(jù)及使用Cookie值的方法

    這篇文章主要介紹了Python模仿POST提交HTTP數(shù)據(jù)及使用Cookie值的方法,通過兩種不同的實現(xiàn)方法較為詳細(xì)的講述了HTTP數(shù)據(jù)通信及cookie的具體用法,需要的朋友可以參考下
    2014-11-11
  • python 實現(xiàn)壓縮和解壓縮的示例

    python 實現(xiàn)壓縮和解壓縮的示例

    這篇文章主要介紹了python 實現(xiàn)壓縮和解壓縮的示例,幫助大家更好的利用python處理文件,感興趣的朋友可以了解下
    2020-09-09
  • python如何爬取個性簽名

    python如何爬取個性簽名

    這篇文章主要為大家詳細(xì)介紹了pythonx抓取個性簽名的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-06-06
  • 如何解決Python中tqdm和zip一起用進(jìn)度條不顯示問題

    如何解決Python中tqdm和zip一起用進(jìn)度條不顯示問題

    這篇文章主要介紹了如何解決Python中tqdm和zip一起用進(jìn)度條不顯示問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-08-08
  • Python爬蟲之Selenium多窗口切換的實現(xiàn)

    Python爬蟲之Selenium多窗口切換的實現(xiàn)

    這篇文章主要介紹了Python爬蟲之Selenium多窗口切換的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12

最新評論

锡林郭勒盟| 佛冈县| 广德县| 武邑县| 汤原县| 客服| 合江县| 佳木斯市| 永康市| 新竹市| 温州市| 东乡族自治县| 隆化县| 武功县| 河北省| 仙居县| 纳雍县| 高邑县| 敦化市| 金堂县| 安乡县| 林芝县| 天等县| 邢台县| 治多县| 镇康县| 彭水| 墨江| 施甸县| 深圳市| 舞钢市| 舞钢市| 舞钢市| 长宁县| 大余县| 河曲县| 资源县| 长泰县| 尼勒克县| 绥江县| 靖远县|