def memo(f):
cache={}
def _f(*args):
print 'cache is ',cache
try:
return cache[args]
except keyerror:
cache[args]=result=f(*args)
return result
except typeerror:
return f(args)
return _f
def fib(n):
"""斐波那契數列
"""if n<=1:return 1
else:return fib(n-1)+fib(n-2)
fib=memo(fib)
fib(5)
看了這段**我也是醉了,不過後來又醒了,這段**是犧牲空間以獲得時間效率大幅提公升的典型演算法舉例。**第13行定義的函式fib是計算斐波那契數列第n個數的值,該函式的演算法時間複雜度將是指數級的,那顯然是不可接受的。**第18行重新定義了函式fib,時間複雜度降為o(n)。如果**全看懂了,本文可以飄過了。如果有疑問的話,本文將利用該段**介紹python變數作用域。
當執行python檔案,python直譯器首先會建立全域性環境,對於本文來說,可以將全域性環境想象為python字典,利用該字典,python直譯器可以根據變數名稱查詢該變數引用的實際物件(從c語言的角度來說就是找到該變數實際引用的記憶體的位址)。全域性環境預設已經存有python內建函式、操作符等。例如,當python直譯器遇到操作符'+',就從全域性環境中查詢到操作符'+'實際引用的物件並呼叫。
當上節**執行到第17行,該全域性環境新增了使用者定義的變數名稱'memo'和'fib',執行第18行時,python直譯器從全域性環境中查詢到'memo'實際引用的物件並呼叫,返回結果用來更新全域性環境中'fib'引用的物件,此時'fib'引用的物件已經不是第13行定義的函式物件,而是第3行定義的函式物件,文章到這裡,應該還不是那麼令人費解。
當執行python函式時,python直譯器會建立frame,我們可以簡單看作是區域性環境,與全域性環境類似也可以想象為python字典。需要說明的是,當定義函式時,該函式物件會儲存當前所在環境的引用,例如第1行定義'memo'函式時,該函式物件會儲存指向全域性環境的引用。而當在第18行呼叫'memo'函式跳轉到第2行時,python直譯器將會建立區域性環境,並在區域性環境中複製該函式物件所儲存的定義該函式時所在環境物件的引用,對於本文,'memo'函式物件儲存的就是指向全域性環境的引用,當執行到第4行時,該區域性環境中又新增了'f'、'cache'和'_f',並且'_f'函式物件會儲存對當前區域性環境的引用,當執行第12行時,返回'_f'函式物件,此時由於該函式物件儲存了對當前區域性環境的引用,因此該區域性環境不會釋放。
當執行到第19行時,python直譯器首先在全域性環境查詢'fib'所引用的函式物件,顯然將根據查詢的結果,執行第3行'_f'函式,與執行'memo'函式類似,首先建立區域性環境,並且複製'_f'函式物件所儲存的區域性環境的引用,即執行'memo'函式所建立區域性環境,並且將'args'新增到當前區域性環境中,當執行第4行時,'cache'變數能在當前區域性環境中找到嗎?顯然不能,那就去上一級區域性環境中查詢,如上文所述,上一級區域性環境中有'f','cache'和'_f',因此可以成功訪問'cache'所引用的物件,當執行第8行時,'f'也可以在上一級區域性環境中找到,那究竟跳轉到哪兒執行呢?在建立上一級區域性環境時,'f'是指向第13行定義的函式物件的,因此將跳轉到第16行執行,此時也會建立區域性環境,而該區域性環境的上一級的環境是全域性環境,因該函式物件是在全域性環境中定義的,如果執行到第17行時,'fib'**能找到呢,當然是在全域性環境中找到並執行,然後呢?然後就是重複本節所述的內容,最終當遞迴條件結束時將會逐步返回。
def memo(f):
cache={}
def _f(*args):
print 'cache is ',cache
try:
return cache[args]
except keyerror:
cache[args]=result=f(*args)
return result
except typeerror:
return f(args)
return _f
def fib(n):
"""斐波那契數列
"""if n<=1:return 1
else:return fib(n-1)+fib(n-2)
def square(n):
return n**2
fib=memo(fib)
print fib(5)
square=memo(square)
print square(5)
對於這段**,你認為square(5)會等於fib(5),也就是square和fib會共享'cache'嗎?
Python語言(五)變數作用域
變數的作用是有範圍的,準確說世上任何事物對外作用都是有範圍限制的。而變數或者符號,背後代表著不同的意思,能對他們求值,就要去在求值的地方能看見它們,這些地方就是變數的作用域。作用域粗略的可以分為區域性作用域和全域性作用域。區域性變數就具有區域性作用域,分為函式內變數 類變數和檔案訪問變數。作用域不同...
python變數作用域
變數作用域 scope 在python中是乙個容易掉坑的地方。什麼是作用域 作用域簡單說就是乙個變數的命名空間。中變數被賦值的位置,就決定了哪些範圍的物件可以訪問這個變數,這個範圍就是命名空間。python賦值時生成了變數名,當然作用域也包括在內。python的作用域一共有4中,分別是 l loca...
Python 變數作用域
g global defchange global g g g change print g change print g 結果 global globalchange def function g function deflocalvar g local defglobalvar global g...