斐波那契數列(黃金分割數列)指的是這樣一個數列 0, 1, 1, 2, 3, 5, 8, 13,特別指出:第0項是0,第1項是第一個1。從第三項開始,每一項都等於前兩項之和。
Python 實現斐波那契數列代碼如下:
實現一:
1 def fibonacci(): 2 num = input("Please input your number\n") 3 i,a,b= 0,0,1 //賦值 4 if int(num) < 0: 5 print("你輸入的數據不合理") 6 elif int(num)== 1: 7 print(a) 8 else: 9 while i < int(num): 10 print(a) 11 #sum = a+b 12 #a = b 13 #b = sum 14 a, b = b, a + b #a, b = b, a + b這里不能寫成 a=b b=a+b,如果寫成這樣,b就不是前兩位相加的值,而是已經被b賦過值的a和b相加的值 15 i+=1 16 fibonacci()
實現二:
使用列表的方式實現
1 def fibonacci(num): 2 fibs = [0,1] 3 for i in range(num-2): 4 fibs.append(fibs[-2]+fibs[-1]) #倒數第二個+倒數第一個數的結果,追加到列表 5 print(fibs) 6 7 fibonacci(5)
實現三:
以上兩種方式,都是直接調用的函數中的print打印,return值為none,因此無法進行復用。
將return為一個序列,可以直接復用該序列。
1 def fibonacci(num): 2 fibs = [0,1] 3 for i in range(num-2): 4 fibs.append(fibs[-2]+fibs[-1]) #倒數第二個+倒數第一個數的結果,追加到列表 5 return(fibs) 6 fibonacci(5)
或者
1 def fab_demo2(max): 2 a, n, b = 0, 0, 1 3 list_demo = [] 4 while n < max: 5 list_demo.append(b) 6 a, b = b, a + b 7 n += 1 8 print(list_demo) 9 return list_demo
實現四:
可以復用了,但是考慮到后期若要存儲在list中的數據量過大,比較吃內存浪費資源,應該怎么辦呢,
此時,考慮到利用 iterable 我們可以把 fab 函數改寫為一個支持 iterable 的 class
1 class Fab(object): 2 def __init__(self,max): 3 self.max = max 4 self.n ,self.a ,self.b = 0 ,0 ,1 5 6 def __iter__(self): #繼承object,重寫__iter__后,自動調用__next__方法,返回r對象 7 return self 8 9 def __next__(self): #此處python2為next,python3為__next__,注意區別 10 if self.n < self.max: 11 r = self.b 12 self.a , self.b = self.b , self.a + self.b 13 self.n += 1 14 return r 15 raise StopIteration() 16 #Fab 類通過 next() 不斷返回數列的下一個數,內存占用始終為常數: 17 for i in Fab(5): 18 print(i) 19 #或者 20 print(next(iter(Fab(5))))
實現五
代碼不夠簡潔,使用yield關鍵字
1 def fab_demo4(max): 2 a,n,b = 0,0,1 3 while n < max: 4 yield b 5 #print b 6 a,b = b,a+b 7 n+=1 8 print(next(fab_demo4(5))) 9 for i in fab_demo4(5): 10 print(i)
僅僅把 print b 改為了 yield b,就在保持簡潔性的同時獲得了 iterable 的效果
yield 的作用就是把一個函數變成一個 generator,帶有 yield 的函數不再是一個普通函數,Python 解釋器會將其視為一個 generator,
調用 fab(5) 不會執行 fab 函數,而是返回一個 iterable 對象!
在 for 循環執行時,每次循環都會執行 fab 函數內部的代碼,執行到 yield b 時,fab 函數就返回一個迭代值,
下次迭代時,代碼從 yield b 的下一條語句繼續執行,而函數的本地變量看起來和上次中斷執行前是完全一樣的,於是函數繼續執行,直到再次遇到 yield。
也可以手動調用 fab(5) 的 next() 方法(因為 fab(5) 是一個 generator 對象,該對象具有 next() 方法)
我們可以得出以下結論:
一個帶有 yield 的函數就是一個 generator,它和普通函數不同,生成一個 generator 看起來像函數調用,但不會執行任何函數代碼,直到對其調用 next()(在 for 循環中會自動調用 next())才開始執行。雖然執行流程仍按函數的流程執行,但每執行到一個 yield 語句就會中斷,並返回一個迭代值,下次執行時從 yield 的下一個語句繼續執行。看起來就好像一個函數在正常執行的過程中被 yield 中斷了數次,每次中斷都會通過 yield 返回當前的迭代值。
yield 的好處是顯而易見的,把一個函數改寫為一個 generator 就獲得了迭代能力,比起用類的實例保存狀態來計算下一個 next() 的值,不僅代碼簡潔,而且執行流程異常清晰。
如何判斷一個函數是否是一個特殊的 generator 函數?可以利用 isgeneratorfunction 判斷:
1 >>> from inspect import isgeneratorfunction 2 >>> isgeneratorfunction(fab) 3 True
要注意區分 fab 和 fab(5),fab 是一個 generator function,而 fab(5) 是調用 fab 返回的一個 generator,好比類的定義和類的實例的區別: