摘要:是一門清晰簡潔的語言,如果你對一些細節不了解的話,就會掉入到那些深不見底的坑里,下面,我就來總結一些里常見的坑。這是個很常見但很容易被忽略的一個坑。
Python是一門清晰簡潔的語言,如果你對一些細節不了解的話,就會掉入到那些深不見底的“坑”里,下面,我就來總結一些Python里常見的坑。
列表創建和引用
嵌套列表的創建
使用*號來創建一個嵌套的list:
li = [[]] * 3 print(li) # Out: [[], [], []]
通過這個方法,可以得到一個包含3個list的嵌套list,我們來給第一個list增加一個元素:
li[0].append(1) print(li) # Out: [[1], [1], [1]]
通過輸出的結果可以看初,我們只給第一元素增加元素,結果三個list都增加了一個元素。這是因為[[]]*3并不是創建了三個不同list,而是創建了三個指向同一個list的對象,所以,當我們操作第一個元素時,其他兩個元素內容也會發生變化的原因。效果等同于下面這段代碼:
li = [] element = [[]] li = element + element + element print(li) # Out: [[], [], []] element.append(1) print(li) # Out: [[1], [1], [1]]
我們可以打印出元素的內存地址一探究竟:
li = [[]] * 3 print([id(inner_list) for inner_list in li]) # Out: [6830760, 6830760, 6830760]
到這我們可以明白原因了。那如何解決了?可以這樣:
li = [[] for _ in range(3)]
這樣我們就創建了三個不同的list對象
print([id(inner_list) for inner_list in li]) # Out: [6331048, 6331528, 6331488]列表元素的引用
不要使用索引方法遍歷list,例如:
for i in range(len(tab)): print(tab[i])
比較好的方法是:
for elem in tab: print(elem)
for語句會自動生成一個迭代器。如果你需要索引位置和元素,使用enumerate函數:
for i, elem in enumerate(tab): print((i, elem))
注意 == 符號的使用
if (var == True): # 當var是:True、1、 1.0、 1L時if條件成立 if (var != True): # 當var不是 True 和 1 時if條件成立 if (var == False): # 當var是 False 或者 0 (or 0.0, 0L, 0j) if條件成立 if (var == None): # var是None if條件成立 if var: # 當var非空(None或者大小為0)對象 string/list/dictionary/tuple, non-0等if條件成立 if not var: # 當var空(None或者大小為0)對象 string/list/dictionary/tuple, non-0等if條件成立 if var is True: # 只有當var時True時 if條件成立 1也不行 if var is False: # 只有當var時False時 if條件成立 0也不行 if var is None: # 和var == None 一致
捕獲異常由于提前檢查
不夠優雅的代碼:
if os.path.isfile(file_path): file = open(file_path) else: # do something
比較好的做法:
try: file = open(file_path) except OSError as e: # do something
在python2.6+的里面可以更簡潔:
with open(file_path) as file:
之所以這么用,是這么寫更加通用,比如file_path給你傳個None就瞎了,還得判斷是不是None,如果不判斷,就又得抓異常,判斷的話,代碼有多寫了很多。
類變量初始化
不要在對象的init函數之外初始化類屬性,主要有兩個問題
如果類屬性更改,則初始值更改。
如果將可變對象設置為默認值,您將獲得跨實例共享的相同對象。
錯誤示范(除非你想要靜態變量) ``` class Car(object): color = "red" wheels = [Wheel(), Wheel(), Wheel(), Wheel()] ``` 正確的做法: ``` class Car(object): def __init__(self): self.color = "red" self.wheels = [Wheel(), Wheel(), Wheel(), Wheel()] ``` **函數默認參數** ``` def foo(li=[]): li.append(1) print(li) foo([2]) # Out: [2, 1] foo([3]) # Out: [3, 1] ``` 該代碼的行為與預期的一樣,但如果我們不傳遞參數呢? ``` foo() # Out: [1] As expected... foo() # Out: [1, 1] Not as expected... ``` 這是因為函數參數類型是定義是確認的而不是運行時,所以在兩次函數調用時,li指向的是同一個list對象,如果要解決這個問題,可以這樣: ``` def foo(li=None): if not li: li = [] li.append(1) print(li) foo() # Out: [1] foo() # Out: [1] ``` 這雖然解決了上述的問題,但,其他的一些對象,比如零長度的字符串,輸出的結果就不是我們想要的。 ``` x = [] foo(li=x) # Out: [1] foo(li="") # Out: [1] foo(li=0) # Out: [1] ``` 最常用的辦法是檢查參數是不是None ``` def foo(li=None): if li is None: li = [] li.append(1) print(li) foo() # Out: [1] ``` **在遍歷時修改**
for語句在遍歷對象是會生成一個迭代器,如果你在遍歷的過程中修改對象,會產生意想不到的結果:
alist = [0, 1, 2] for index, value in enumerate(alist): alist.pop(index) print(alist) # Out: [1]
第二個元素沒有被刪除,因為迭代按順序遍歷索引。上述循環遍歷兩次,結果如下:
# Iteration #1 index = 0 alist = [0, 1, 2] alist.pop(0) # removes "0" # Iteration #2 index = 1 alist = [1, 2] alist.pop(1) # removes "2" # loop terminates, but alist is not empty: alist = [1]
如果避免這個問題了,可以創建另外一個list
alist = [1,2,3,4,5,6,7] for index, item in reversed(list(enumerate(alist))): # delete all even items if item % 2 == 0: alist.pop(index) print(alist) # Out: [1, 3, 5, 7]
整數和字符串定義
python預先緩存了一個區間的整數用來減少內存的操作,但也正是如此,有時候會出很奇特的錯誤,例如:
>>> -8 is (-7 - 1) False >>> -3 is (-2 - 1) True
另外一個例子
>>> (255 + 1) is (255 + 1) True >>> (256 + 1) is (256 + 1) False
通過不斷的測試,會發現(-3,256)這區間的整數都返回True,有的甚至是(-8,257)。默認情況下,[-5,256]會在解釋器第一次啟動時創建并緩存,所以才會有上面的奇怪的行為。這是個很常見但很容易被忽略的一個坑。解決方案是始終使用equality(==)運算符而不是 identity(is)運算符比較值。
Python還保留對常用字符串的引用,并且可以在比較is字符串的身份(即使用)時產生類似的混淆行為。
>>> "python" is "py" + "thon" True
python字符串被緩存了,所有python字符串都是該對象的引用,對于不常見的字符串,即使字符串相等,比較身份也會失敗。
>>> "this is not a common string" is "this is not" + " a common string" False >>> "this is not a common string" == "this is not" + " a common string" True
所以,就像整數規則一樣,總是使用equal(==)運算符而不是 identity(is)運算符比較字符串值。
列表推導和循環中的變量泄漏
有個例子:
i = 0 a = [i for i in range(3)] print(i) # Outputs 2
python2中列表推導改變了i變量的值,而python3修復了這個問題:
i = 0 a = [i for i in range(3)] print(i) # Outputs 0
類似地,for循環對于它們的迭代變量沒有私有的作用域
i = 0 for i in range(3): pass print(i) # Outputs 2
這種行為發生在Python 2和Python 3中。
為了避免泄漏變量的問題,請在列表推導和for循環中使用新的變量。
or操作符
例如
if a == 3 or b == 3 or c == 3:
這個很簡單,但是,再看一個:
if a or b or c == 3: # Wrong
這是由于or的優先級低于==,所以表達式將被評估為if (a) or (b) or (c == 3):。正確的方法是明確檢查所有條件:
if a == 3 or b == 3 or c == 3: # Right Way
或者,可以使用內置函數any()代替鏈接or運算符:
if any([a == 3, b == 3, c == 3]): # Right
或者,為了使其更有效率:
if any(x == 3 for x in (a, b, c)): # Right
更加簡短的寫法:
if 3 in (a, b, c): # Right
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/44015.html
摘要:熵增原理自發的有序是不存在的我坦白這一點是過于復雜的物理概念,我解釋不明白,但結論能夠最簡單的說明有序必須在某種介入之下完成。還是熵增原理那就容易理解為什么數據的準確和恒定,對計算機是如此的重要。 來自這個問題的答案。 人類思維和智能的本質是什么?思考這個問題,也許能讓我們更好的了解計算機和人類自己。 ——甚至某種方面上來看,我都有點覺得:計算機其實就是我們自己…… 人類總體上是...
閱讀 3593·2021-11-23 09:51
閱讀 2795·2021-11-23 09:51
閱讀 676·2021-10-11 10:59
閱讀 1672·2021-09-08 10:43
閱讀 3223·2021-09-08 09:36
閱讀 3289·2021-09-03 10:30
閱讀 3293·2021-08-21 14:08
閱讀 2195·2021-08-05 09:59