為什麼 Python 不是 lexical scoping?

時間 2021-05-06 19:16:19

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

print

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

;print

(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...