python變數作用域中容易忽略的點

weixin_33782386發表於2017-07-09

python中變數作用於並不陌生,函式中的是區域性變數,先看一個小例子:

In [1]: def f1(a):
   ...:     print(a)
   ...:     print(b)

呼叫

f1(3)

很明顯這個會報錯

NameError                                 Traceback (most recent call last)
<ipython-input-3-a636accabfae> in <module>()
----> 1 f1(3)

<ipython-input-1-8c139ea215ce> in f1(a)
      1 def f1(a):
      2     print(a)
----> 3     print(b)
      4

NameError: name 'b' is not defined

這時我們需要新增對b的賦值操作

b = 5

在執行一下

In [5]: f1(3)
3
5

說明在執行函式時函式會去全域性變數中找b的值

這點明白之後我們再來看一個讓人有點吃驚的例子:

In [6]: b = 6

In [7]: def f1(a):
   ...:     print(a)
   ...:     print(b)
   ...:     b = 9

看完函式你一定會覺得列印時候b應該顯示6吧,我們看看結果

UnboundLocalError                         Traceback (most recent call last)
<ipython-input-8-a636accabfae> in <module>()
----> 1 f1(3)

<ipython-input-7-b4880e75da42> in f1(a)
      1 def f1(a):
      2     print(a)
----> 3     print(b)
      4     b = 9
      5

UnboundLocalError: local variable 'b' referenced before assignment

什麼?報錯了,顯示本地變數在賦值前使用!

事實是:python編譯函式的定義體時,判斷b是區域性變數,所以在執行時會獲取b之前沒有定義,所以報錯,我們將b的定義放到列印之前就好了,這恰恰說明了python呼叫的過程順序,先區域性,後全域性。

還有一種解決辦法就是在使用b之前使用global宣告b要用全域性變數裡面的

如果還想進一步看看直譯器的載入內容,可以使用python的dis模組來檢視,過程更加清晰。

相關文章