背景
在聯系pyhon基礎時候,遇到一個百思不解的問題,于是扒拉了一下,
廖雪峰官網python 高級特性-生成器 章節
在課后聯系 楊輝三角形程序中遇到的坑
先看現象

怎么和自己預期的不一樣呢?難道自己抄的楊輝三角形定義都能出錯? 于是我抱著懷疑的態度去列印了一下 triangles()

完全沒有問題呀? 怎么上面的運行結果全是最后一行,即第10行的呢?這么詭異!?(其實看到結果我心里已經預感到出問題的地方了,只是想去理清一下其中的邏輯,順便加深一下印象,后面才能避免類似的坑)
扒它的衣服看里面
其實我當我看到結果的時候,我就猜到多半是定義變數時候,變數指向的問題,為了看清楚并解決疑惑,必須得找到python中好用的兩個工具函式:判斷兩個變數是否指向同一個物件 id() 和 a is b
- 好的扒衣服開始:
先把代碼放到pycharm中,方便進行除錯
def triangles():
ret = [1]
while True:
yield ret
for i in range(1, len(ret)):
ret[i] = pre[i] + pre[i - 1]
ret.append(1)
pre = ret[:]
# 期待輸出:
# [1]
# [1, 1]
# [1, 2, 1]
# [1, 3, 3, 1]
# [1, 4, 6, 4, 1]
# [1, 5, 10, 10, 5, 1]
# [1, 6, 15, 20, 15, 6, 1]
# [1, 7, 21, 35, 35, 21, 7, 1]
# [1, 8, 28, 56, 70, 56, 28, 8, 1]
# [1, 9, 36, 84, 126, 126, 84, 36, 9, 1]
n = 0
results = []
for t in triangles():
results.append(t)
n = n + 1
if n == 10:
break
for t in results:
print(t)
if results == [
[1],
[1, 1],
[1, 2, 1],
[1, 3, 3, 1],
[1, 4, 6, 4, 1],
[1, 5, 10, 10, 5, 1],
[1, 6, 15, 20, 15, 6, 1],
[1, 7, 21, 35, 35, 21, 7, 1],
[1, 8, 28, 56, 70, 56, 28, 8, 1],
[1, 9, 36, 84, 126, 126, 84, 36, 9, 1]
]:
print('測驗通過!')
else:
print('測驗失敗!')
打上斷點,前面走幾步好看看它走路的曼妙身姿,前面的每一步我都要去細品一番

開始除錯跟蹤,這個程序比較多,我就不一一截圖細說,畢竟有些東西要自己去細品才有味道,我這里上幾個關鍵的點進行分析
通過debug 配合 f9 進行單步除錯即可,除錯程序中看關鍵變數的變化
外層的關鍵變數: results , t
triangles中的關鍵變數:ret , pre
當回圈跟到第二圈時候:
results[[1,1]] t[1,1]
ret[1,1] pre[1,1]

triangles內部
id(ret)
2355532678728
id(ret[0])
140735827321232
id(ret[1])
140735827321232
id(pre)
2355532554568
id(pre[0])
140735827321232
id(pre[1])
140735827321232
外層
id(results)
2355532610376
id(results[0])
2355532678728
id(t)
2355532678728
id(t[0])
140735827321232
id(t[1])
140735827321232
可以看出,t就是 yield ret, 關鍵點: results中的元素,是可變的,直接指向了ret
比如 results[0] 指向了ret, 而ret每執行一次,就會變成楊輝三角行的下一行,這就導致了results[0] 不在是固定的 1,results[1] 不是固定的[1,1] 進而導致上面的結果,
我再畫一下第三遍的結果圖
results[[1,3,3,1] ,[1,3,3,1] ,[1,3,3,1]] t[1,3,3,1]
ret[1,3,3,1] pre[1,3,3,1]

id(results)
2355532610376
id(results[0])
2355532678728
id(results[1])
2355532678728
id(results[2])
2355532678728
id(ret)
2355532678728
id(ret[0])
140735827321232
id(ret[1])
140735827321296
id(ret[2])
140735827321296
id(ret[3])
140735827321232
到這里其實已經扒完了,根本原因就是results 中存入的是變數,改變數指向的是 ret, ret沒執行一遍,就會變成楊輝三角行的下一行,
既然知道了原因,需要怎么修改呢?
只要yield ret 回傳的物件不指向ret即可,我們把它換成 ret的復制,類似下面pre 一樣,修改辦法 yield ret 修改 為 yield ret[:]
yield ret ->修改為 yield ret[:]
修改后的邏輯:

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/41847.html
標籤:其他
