2014-02-24 44 views
0

我已閱讀以下文章,但我仍然不確定。瞭解Python如何「編譯」或「解釋」函數對象

  1. Python Compilation/Interpretation Process

  2. Why python compile the source to bytecode before interpreting?

如果我有包含以下代碼一個Python文件myfunctions.py。

x = 3 
def f(): 
    print x 
    x = 2 

然後,說$ python myfunctions.py運行非常好。 但是現在對上述文件做一個小改動。新文件如下所示。

x = 3 
def f(): 
    print x 
    x = 2 
f() # there is a function call now 

這一次,代碼給出了一個錯誤。現在,我正試圖理解這種行爲。到目前爲止,這些都是我的結論。

  • 的Python創建x=3
  • 字節碼它創建了一個函數對象樓快速掃描並具有字節碼談到了局部變量F公司範圍內,但注意,Python中的所有語句的字節碼是不可能一直建。
  • 現在,Python遇到一個函數調用,它知道這個函數調用是合法的,因爲只有最低字節碼談論函數對象f及其局部變量。
  • 現在解釋採取負責執行的字節碼,但是從最初的足跡它知道x是一個局部變量這裏說 - 「你爲什麼分配之前您在打印」

可有人請對此有何評論?提前致謝。對不起,如果這已被解決。

+2

我認爲額外的縮進不在你的實際文件中,並且該異常是'UnboundLocalError'? – mgilson

+0

什麼是錯誤?在第二個例子中,縮進應該在「def」行中被打破嗎? – tripleee

+0

我得到的錯誤(固定縮進之後)是'UnboundLocalError:本地變量'x'在作業之前引用了' –

回答

2

當解釋器讀取函數時,對於遇到的每個「名稱」(變量),解釋程序決定該名稱是本地還是非本地。使用的標準非常簡單...在這個名稱的正文的任何​​地方是否有一個賦值語句(禁止global語句)?例如: -

def foo(): 
    x = 3 # interpreter will tag `x` as a local variable since we assign to it here. 

如果有一個賦值語句該名稱,然後名稱被標記爲「本地」,否則,它就會被標記爲非本地。

現在,你的情況,你試圖打印的標記成局部變量,但是你做你實際上已經達到了臨界賦值語句如此前。 Python尋找本地名稱,但沒有找到它,所以它引發了UnboundLocalError

Python是非常動態的,允許你做很多瘋狂的事情,這是什麼使得它如此強大的一部分。這種方法的缺點是,它變得非常困難檢查這些錯誤,除非你確實運行功能 - 事實上,Python已經做出決定檢查比其他的語法什麼,直到運行該功能。這就解釋了爲什麼在實際調用函數之前你永遠不會看到異常。


如果你想蟒蛇標記該變量作爲全局的,你可以用一個明確的global 聲明這樣做:

x = 3 
def foo(): 
    global x 
    print x 
    x = 2 

foo() # prints 3 
print x # prints 2 

python3.x將此概念更進一步介紹了nonlocal關鍵字

+0

謝謝你的回答。但是當Python遇到一個函數定義時,顯然它正在執行一些範圍檢查並跟蹤調用該函數時將要使用的變量。 否則,它遇到的第一個x應該是全局x(= 3),對吧?然後一個本地的x(= 2)會出現嗎? 但是Python明確地分析了變量是局部變量和全局變量的整個函數體,即使在函數被調用之前語句沒有被執行。 – Killer

+0

@Killer - 正確。它在讀取函數時通過本地或非本地*來獲取變量,而不是當它被執行時。 – mgilson

+0

謝謝@mgilson。 – Killer

1

mgilson得到了一半的答案。

另一半是Python不會去尋找超出它不會執行的函數(或函數對象)的語法錯誤之外的錯誤。因此,在第一種情況下,由於f()未被調用,因此未檢查操作順序錯誤。

在這方面,它不像C和C++,它要求所有的東西都要在前面完全聲明。它有點像C++模板,在代碼實際實例化之前,可能無法找到模板代碼中的錯誤。

+0

謝謝你,@Mike。現在更清楚這些事情。 – Killer