作用域(全局變量和局部變量)


變量到底是什么呢?可將其視為指向值的名稱。因此,執行賦值語句x = 1后,名稱x指向值1。這幾乎與使用字典時一樣(字典中的鍵指向值),只是你使用的是“看不見”的字典。實際上,這種解釋已經離真相不遠。有一個名為vars的內置函數,它返回這個不可見的字典:

>>> x = 1
>>> scope = vars()
>>> scope['x']
1
>>> scope['x'] += 1
>>> x
2

警告 一般而言,不應修改vars返回的字典,因為根據Python官方文檔的說法,這樣做的結果是不確定的。換而言之,可能得不到你想要的結果。

這種“看不見的字典”稱為命名空間作用域。那么有多少個命名空間呢?除全局作用域外,每個函數調用都將創建一個。

>>> def foo(): x = 42
...
>>> x = 1
>>> foo()
>>> x
1

在這里,函數foo修改(重新關聯)了變量x,但當你最終查看時,它根本沒變。這是因為調用foo時創建了一個的命名空間,供foo中的代碼塊使用。賦值語句x = 42是在這個內部作用域(局部命名空間)中執行的,不影響外部(全局)作用域內的x。在函數內使用的變量稱為局部變量(與之相對的是全局變量)。參數類似於局部變量,因此參數與全局變量同名不會有任何問題。

>>> def output(x): print(x)
...
>>> x = 1
>>> y = 2
>>> output(y)
2

到目前為止一切順利。但如果要在函數中訪問全局變量呢?如果只是想讀取這種變量的值(不重新關聯它),通常不會有任何問題。

>>> def combine(parameter): print(parameter + external)
...
>>> external = 'berry'
>>> combine('Shrub')
Shrubberry

警告 像這樣訪問全局變量是眾多bug的根源。務必慎用全局變量。

“遮蓋”的問題

讀取全局變量的值通常不會有問題,但還是存在出現問題的可能性。如果有一個局部變量或參數與你要訪問的全局變量同名,就無法直接訪問全局變量,因為它被局部變量遮住了。

如果需要,可使用函數globals來訪問全局變量。這個函數類似於vars,返回一個包含全局變量的字典。(locals返回一個包含局部變量的字典。)

例如,在前面的示例中,如果有一個名為parameter的全局變量,就無法在函數combine中訪問它,因為有一個與之同名的參數。然而,必要時可使用globals()['parameter']來訪問它。

>>> def combine(parameter):
...     print(parameter + globals()['parameter'])
...
>>> parameter = 'berry'
>>> combine('Shrub')
Shrubberry

重新關聯全局變量(使其指向新值)是另一碼事。在函數內部給變量賦值時,該變量默認為局部變量,除非你明確地告訴Python它是全局變量。那么如何將這一點告知Python呢?

>>> x = 1
>>> def change_global():
...     global x
...     x = x + 1
...
>>> change_global()
>>> x
2

 作用域嵌套

Python函數可以嵌套,即可將一個函數放在另一個函數內,如下所示:

def foo():
    def bar():
        print("Hello, world!")
    bar()

嵌套通常用處不大,但有一個很突出的用途:使用一個函數來創建另一個函數。這意味着可像下面這樣編寫函數:

def multiplier(factor):
    def multiplyByFactor(number):
        return number * factor
    return multiplyByFactor

在這里,一個函數位於另一個函數中,且外面的函數返回里面的函數。也就是返回一個函數,而不是調用它。重要的是,返回的函數能夠訪問其定義所在的作用域。換而言之,它攜帶着自己所在的環境(和相關的局部變量)!

每當外部函數被調用時,都將重新定義內部的函數,而變量factor的值也可能不同。由於Python的嵌套作用域,可在內部函數中訪問這個來自外部局部作用域(multiplier)的變量,如下所示:

作用域嵌套函數的調用方式:

def multiplier(factor):
    def multiplyByFactor(number):
        return number * factor
    return multiplyByFactor

>>> double = multiplier(2)
>>> double(5)
10
>>> triple = multiplier(3)
>>> triple(3)
9
>>> multiplier(5)(4)
20

multiplyByFactor這樣存儲其所在作用域的函數稱為閉包

通常,不能給外部作用域內的變量賦值,但如果一定要這樣做,可使用關鍵字nonlocal。這個關鍵字的用法與global很像,讓你能夠給外部作用域(非全局作用域)內的變量賦值。

global和nonlocal區別:

第一,兩者的功能不同。global關鍵字修飾變量后標識該變量是全局變量,對該變量進行修改就是修改全局變量,而nonlocal關鍵字修飾變量后標識該變量是上一級函數中的局部變量,如果上一級函數中不存在該局部變量,nonlocal位置會發生錯誤(最上層的函數使用nonlocal修飾變量必定會報錯)。

第二,兩者使用的范圍不同。global關鍵字可以用在任何地方,包括最上層函數中和嵌套函數中,即使之前未定義該變量,global修飾后也可以直接使用,而nonlocal關鍵字只能用於嵌套函數中,並且外層函數中定義了相應的局部變量,否則會發生錯誤(見第一)。
詳細說明地址:https://blog.csdn.net/xcyansun/article/details/79672634

函數id()的用法:

功能:返回變量地址

也就是is對比為真的根源,地址相同則相同為真,而相等並不一定相同。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM