1樓:
先說scope,scope其實就是namespace,是name而不是value。 Lexical/static scope顧名思義函式的scope取決於被定義時的context,可以從文字推知。反之dynamic scope則取決於呼叫被定義時的context。
題主給的例子裡inner的x的確實是定義是foo函式裡x,即使在外部被呼叫也一樣,這恰恰說明了python是lexical scope,並且如果你返回inner函式是會形成乙個包含了自由變數x的closure的,而不會造成變數未定義的錯誤。
那為什麼是4不是2呢,這單純地和語句被執行的順序有關。題主在這裡其實是犯了乙個更加基礎的概念的錯誤,那就是函式在被定義時不會被執行,而是在呼叫時被執行的,如果你把print語句放在x的第二次賦值之前,結果就會是2了。
關於dynamic scope, @Guannan Wei 的答案裡有兩個絕佳的例子。
2樓:cwaar
首先,按照LEGB原則, 閉包inner封裝的確實是foo裡所定義的區域性變數x。這同時符合lexical scoping定義。
再者(這很關鍵),閉包只有再被呼叫的那一刻才從外層scope裡查詢變數,這時候x已經被修改成為3.
那麼問題來了,我就是要封裝x=1那一刻的值,如何做呢?可以如下deffoo
():x=1
definner(x
=x):returnx+
1x=3
inner(x
)這樣使得定義inner函式的時候,我們就給它的乙個區域性變數選取了乙個預設值,即為外圍函式的區域性變數的當前值,並將其封存在自己的區域性變數裡。
3樓:alexsunmiu
題主所說的現代化的程式語言指的是什麼? js經過這麼多代的更新迭代,現在也是這樣~
(function
foo()x=
3;console
.log
(inner
());
})();
正常的閉包特性吧~
4樓:非典型普通人類
這個問題很好回答:x是inner函式的環境變數,所以在inner的定義中出現的x其實就是對定義外面的,也就是inner的環境變數的乙個引用而已。
函式只有在被呼叫的時候才會執行,你前面將置為1,後面又改為3,不過是改變了x的引用值而已,相當於給x重新賦值。然後執行inner函式,使用x所對應的值為3,因此答案就是4了。
5樓:rainoftime
deffoo():x=
1def
inner
():returnx+
1x=3
inner
()foo
()# 輸出4
為什麼輸出4而不是2?
有這個感覺,是因為對詞法作用域(靜態作用域)的理解不夠充分。
有人可能會怎麼想:靜態作用域嘛,所以是靜態決定的,inner定義時「捕獲」到引用環境x=1。所以呼叫時應該返回2。關鍵是:捕獲的是x的引用,而非值。
呼叫foo,最後print的時候inner才執行。x已經由1變為了3。如果把print inner()放在x = 3這行前面,自然會輸出2
---題外話---
關於python不是lexical scoping,是有這個說法的,或者說是:不支援「完整的」詞法作用域。比如不能在inner中對外部的變數賦值(Python3增加了nonlocal關鍵字解決了這個問題)
6樓:吳璽煜
我Python2.x和3.x混用了
definner
():x=1
returnx+
1def
foo():x=
3print
(inner
())如果py是動態作用域,這樣就是4了。。。。
結果是2。上面大神已經說的很明白了
補充:這樣也能2了
deffoo
():x=1
definner
():returnx+
1print
inner()x=3
7樓:
import
inspect
deffoo
():x=1
printid(
inspect
.currentframe
()),
inspect
.currentframe().
f_locals
.keys
()def
inner
():f_c
=inspect
.currentframe
()printid(
f_c),
f_c.
f_locals
.keys
()printid(
f_c.
f_back
),f_c
.f_back
.f_locals
.keys
()returnx+
1printid(
inspect
.currentframe
()),
inspect
.currentframe().
f_locals
.keys()x
=3print
inner
()foo
()### 輸出:
30846736
['x'
]30846736
['x'
,'inner'
]30847096
['x'
,'f_c'
]30846736
['x'
,'inner']4
把 frame 的位址打出來就清楚了.
8樓:
你以為Python是
letfoo()=
letx=1
inlet
inner()=
x+1in
letx=3
inprint
(inner())
實際上Python是
letfoo()=
letx
=ref1in
letinner()=
!x+1
inx:=3
(inner())
這和lexical scoping一點關係都沒有啊這是個mutable vs immutable的問題python的scope是這樣的
def foox = 1def innerreturn x + 1x = 3print inner
你認為的scope是這樣的
let foolet x = 1 inlet inner () = x + 1 inlet x = 3 inprint (inner
因為Python的scope是mutable的,所以x = 3只是把x的binding修改成指向3
就是這樣
Python 為什麼會流行?
簡簡單單 方不方便提供一下你的資料和要求我乙個python小白想嘗試一下 python能在資料分析領域火起來就是因為對陣列處理方便。 w甜甜 但是人家支援C和C 拓展 你大可以自己拓展乙個 完備的流 完全遵循蛇形風格 的優秀的,第三方的,excel庫 無能狂怒就說無能狂怒 說的那麼冠冕堂皇幹嘛 wy...
為什麼Python執行textmobject()裡的公式寫法和latex寫法差乙個 ?
錦恢 盲猜題主在玩manim的Demo。不只是Python,許多通用程式語言都會將字串中的 識別成轉義符,我們可以看乙個簡單的例子 a t print a 你會發現 t 被解釋成了製表符而非 與 t 因此 不是正常可以列印的字元,那麼怎麼列印 呢?那就再加乙個 讓它自己被自己轉義成一般的字元 a p...
你為什麼用 Python?
許建國 我主要工作是平面設計,對於批量操作ps ai id,python是目前我所知最合適的 很方便從網路獲取資料,很方便從各種格式讀取資料,很方便呼叫imagemagick ffmpeg ghostscript potrace poppler等命令列工具,還有win32com可以直接操作adobe...