以前跟你們已經講了有關函數的一部分知識,可是忘了講一個很重要的點,就是變量的做用域,這塊知識不僅是適用於函數,它試用域全部的Python程序python
在正式寫程序以前,必需要清楚這一塊,不然就很容易犯錯誤閉包
變量能夠咱們能夠將它看爲指向值的名稱,就像咱們以前講的字典同樣的,只是這個字典你是看不到,固然這是很通俗的解釋,但也離真相不遠了函數
在Python中有一個vars的內置函數,他能夠返回這個看不見的「字典」spa
好比如下代碼blog
In [1]: a = 100 In [2]: distrue = vars() In [3]: distrue["a"] Out[3]: 100 In [4]: distrue["a"] += 100 In [5]: a Out[5]: 200
是否是很是神奇,把變量變成了一個鍵值對應的字典,並且還能夠經過索引更改值索引
在這裏要注意一點,根據官方文檔,是不該該修改vars返回的字典的,這樣會使得結果不肯定作用域
咱們把這種看不見的字典叫作命名空間或者是做用域文檔
咱們如今給出如下代碼class
In [7]: a = 100 In [8]: def func_one(): ...: a = 200 ...: In [9]: func_one() In [10]: a Out[10]: 100
一開始,咱們定義了一個變量,將100賦值給了a,而後咱們後面定義了一個方法,將200賦值給a變量
以後,咱們調用了這個方法,可是,最後a的值並無改變,這個就牽涉到有關變量做用域的問題了,咱們慢慢解釋
首先咱們調用func_one時是建立了一個新的命名空間,以供func_one中的代碼塊使用,而賦值語句a = 200是在這個函數內部的做用域執行的,也就是一個局部命名空間,他是不會影響外部做用域(或者是全局)的變量,
在函數內部使用的變量咱們把它成稱爲局部變量,在函數外的就稱做全局變量
參數是相似於局部變量的,因此他的命名即便與全局變量相同也是沒有關係的
好比下面的一個輸出函數
In [12]: def output(x): ...: print(x) ...: In [13]: x = 10 In [14]: y = 20 In [15]: output(y) 20 In [16]: output(x) 10
只是讀取值得話,很是簡單
好比如下代碼
In [18]: def linkval(words): ...: print(words + external) ...: In [19]: external = " susmote" In [20]: linkval("hello") hello susmote
可是,在這提醒如下,這種方法仍是慎用,很容易形成bug
這個時候,咱們又遇到了一個新的問題,若是局部變量和全局變量相同的話,就會出現遮蓋的問題
稍微改一下上面的代碼,問題就出現了
In [21]: def linkval(words): ...: external = " jack ma" ...: print(words + external) ...: In [22]: external = " susmote" In [23]: linkval("hello") hello jack ma
也就是說,全局變量被局部變量給遮住了
若是實在有須要的話,可使用globals函數來訪問全局變量,他會返回一個包含全局變量的字典,也就是說能夠經過字典的鍵索引獲取值
(相對的locals返回一個包含局部變量的值)
仍是上面的代碼,咱們稍稍作一點改變,結果就會大相徑庭
In [24]: def linkval(words): ...: external = " jack ma" ...: print(words + globals()['external']) ...: In [25]: external = " susmote" In [26]: linkval("hello") hello susmote
通常咱們在函數中定義變量,它默認是局部變量,可是咱們能夠直接聲明定義的變量爲全局變量,這時咱們就必須用到global這個關鍵詞了
In [32]: a = 100 In [33]: def func_one(): ...: global a ...: a += 100 ...: In [34]: func_one() In [35]: a Out[35]: 200 In [36]: func_one() In [37]: a Out[37]: 300
以前有一個概念沒有講到,就是函數的定義是能夠嵌套的,相似於一個函數中,還能夠定義函數,相似於如下代碼
In [45]: def func_one(): ...: def func_two(): ...: print("內層函數") ...: print("外層函數") ...: func_two() ...: In [46]: func_one() 外層函數 內層函數
嵌套函數實際做用並不大,但他的一個突出的功能仍是不錯的,使用一個函數來建立另外一個函數
例如如下代碼
In [48]: def adder(factor): ...: def addByFactor(number): ...: return number + factor ...: return addByFactor ...: ...: In [49]: adder(10)(10) Out[49]: 20 In [50]: adder(100)(100) Out[50]: 200
一個函數位於另外一個函數中,並且外面的函數返回的是裏面的函數,沒有調用這個函數
其中,最重要的一點是,返回的函數可以訪問其定義所在的做用域,也就是說,他返回時,還帶着他本身所在的環境(相關的局部變量)
放到實際中來講就是能夠在內部函數中訪問這個來自外部做用域的局部變量
咱們把這種函數稱之爲 閉包
若是要給外部做用域的變量賦值,能夠用nonlocal關鍵詞,這有點相似於global
關於做用域我要講的就是這些,經過簡單的練習,就能很快理解