深入了解Python 變數作用域

2022-09-28 21:09:29 字數 3940 閱讀 2065

特點

python的作用域是靜態的,在源**中變數名被賦值的位置決定了該變數能被訪問的範圍。即python變數的作用域由變數所在源**中的位置決定。python中並不是所有的語句塊中都會產生作用域。只有當變數在module(模組)、class(類)、def(函式)中定義的時候,才會有作用域的概念。

1. 函式內部的變數,函式外部不能訪問

def func():

variable = 100

print(variable)

print(variable) # name 'variable' is not defined

2. 函式上層的變數(標量)只能讀取,不能再次定義,初始化

def counter1():

n = 0

def compute():

n = n + 1 # n為標量(數值,字串,浮點數),python程式會因為「如果內部函式有引用外部函式的同名變數或者全域性變數,並且對這個變數有修改.那麼python會認為它是乙個區域性變數,又因為函式中沒有n的定義和賦值,所以報錯

# y = n + 1 # 更改為y就沒事

# return y

return n

return compute

variab = 300

def test_scopt():

print(variable) # 此時呼叫區域性變數variable並有沒繫結到乙個記憶體物件(沒有定義和初始化,即沒有賦值)。本質上還是遵循的legb法則

variable = 200 #因為這裡,前面呼叫過一次,所以variable就變為了區域性變數

# print(variable) # 寫在下面就沒問題,因為variable是新的區域性變數,而不是重新被定義,卻沒有繫結

test_scopt()

python中的模組**在執行之前,並不會經過預編譯,但是模組內的函式體**在執行前會經過預編譯,因此不管變數名的繫結發生在作用域的那個位置,都能被編譯器知道。python雖然是乙個靜態作用域語言,但變數名查詢是動態發生的,直到在程式執行時,才會發現作用域方面的問題,

3. list,dict等復合變數裡面的值都可以引用更改

def counter():

n = [0]

def compute():

n[0] += 1 # 更改的是n裡面的第乙個值,不是更改n

return n[0]

return compute

func = counter()

func() # 1

func() # 2

func() # 3

4. global 宣告全域性變數,如果在區域性要對全域性變數修改,需要在區域性也要先宣告該全域性變數

def counter1():

n = 0

def compute():

global n # 如果在區域性要對全域性變數修改,需要在區域性也要先宣告該全域性變數,但此處也會報錯,因為沒有全域性變數n

n += 1

return n

return compute

# right

def counter1():

global n

n = 0

def compute():

global n

n += 1

return nspoxdgf

return compute

5. nonlocal關鍵字用來在函式或其他作用域中使用外層(非全域性)變數

def make_counter():

count = 0

def counter():

nonlocal count # 使用外層非全域性變數

count += 1

return count

return counter

作用域的型別

在python中,使用乙個變數時並不嚴格要求需要預先宣告它,但是在真正使用它之前,它必須被繫結到某個記憶體物件(被定義、賦值);這種變數名的繫結將在當前作用域中引入新的變數,同時遮蔽外層作用域中的同名變數。

l(local)區域性作用域

區域性變數:包含在def關鍵字定義的語句塊中,即在函式中定義的變數。每當函式被呼叫時都會建立乙個新的區域性作用域。python中也有遞迴,即自己呼叫自己,每次呼叫都會建立乙個新的區域性命名空間。在函式內部的變數宣告,除非特別的宣告為全域性變數,否則均預設為區域性變數。有些情況需要在函式內部定義全域性變數,這時可以使用global關鍵字來宣告變數的作用域為全域性。區域性變數域就像乙個 棧,僅僅是暫時的存在,依賴建立該區域性作用域的函式是否處於活動的狀態。所以,一般建議盡量少定義全域性變數,因為全域性變數在模組檔案執行的過程中會一直存在,占用記憶體空間。

注意:如果需要在函式內部對全域性變數賦值,需要在函式內部通過global語句宣告該變數為全域性變數。

e(enclosing)巢狀作用域

e也包含在def關鍵字中,e和l是相對的,e相對於更上層的函式而言也是l。與l的區別在於,對乙個函式而言,l是定義在此函式內部的區域性作用域,而e是定義在此函式的上一層父級函式的區域性作用域。主要是為了實現python的閉包,而增加的實現。

g(global)全域性作用域

即在模組層次中定義的變數,每乙個模組都是乙個全域性作用域。也就是說,在模組檔案頂層宣告的變數具有全域性作用域,從外部開來,模組的全域性變數就是乙個模組物件的屬性。

注意:全域性作用域的作用範圍僅限於單個模組檔案內

b(built-in)內建作用域

系統內固定模組裡定義的變數,如預定義在builtin 模組內的變數。

作用域鏈:變數名解www.cppcns.com析legb法則

搜尋變數名的優先順序:區域性作用域 > 巢狀作用域 > 全域性作用域 > 內建作用域

legb法則: 當在函式中使用未確定的變數名時,python會按照優先順序依次搜尋4個作用域,以此來確定該變數名的意義。首先搜尋區域性作用域(l),之後是上一層巢狀結構中def或lambda函式的巢狀作用域(e),之後是全域性作用域(g),最後是內建作用域(b)。按這個查詢原則,在第一處找到的地方停止。如果沒有找到,則會出發nameerror錯誤。

example 1

name = "lzl"

def f1():

print(name)

def f2():

name = "eric"

f1()

f2() # 在函式未執行之前,作用域鏈就已經形成了,此時f1()的上一級應該name = 'lzl'

example 2

def scope_test():

def do_local():

spam = "local spam" # 此函式定義了另外的乙個spam字串變數,並且生命週期只在此函式內。此處的spam和外層的spam是兩個變數,如果寫出spam = spam + 「local spam」 會報錯

def do_nonlocal():

nonlocal spam # 使用外層的spam變數 test spam

spam = "nonlocal spam"

def do_global():

global spam

spam = "global spam"

spam = "test spam"

do_local()

print("after local assignmanent:", spam) # test spam

do_nonlocal(www.cppcns.com)

print("after nonlocal assignment:",spam) # nonlocal spam

do_g程式設計客棧lobal()

print("after global assignment:",spam) # nonlocal spam ???? 先找是本地變數,找到的本地變數已經在do_nonlocal()裡面改變了所以輸出的是nonlocal spam

scope_test()

print("in global scope:",spam) # global spam

深入了解Python中的變數

目錄 變數,英文叫做 variable。在 電腦科學概述 中是這樣定義的,高階程式語言允許使用描述性的名字指向主儲存器中的位置,而不必再使用數字位址,這樣的名字稱為變數 variable 之所以是這樣取名是因為,隨著程式的執行,只要改變儲存在這個位置裡的值,那麼與改名字相聯絡的值就會改變。從形式上看...

深入了解A

一 前言 在這裡我將對a 演算法的實際應用進行一定的 並且舉乙個有關a 演算法在最短路徑搜尋的例子。值得注意的是這裡並不對a 的基本的概念作介紹,如果你還對a 演算法不清楚的話,請看姊妹篇 初識a 演算法 這裡所舉的例子是參考amit主頁中的乙個源程式,使用這個源程式時,應該遵守一定的公約。二 a ...

深入了解A

一 前言 在這裡我將對a 演算法的實際應用進行一定的 並且舉乙個有關a 演算法在最短路徑搜尋的例子。值得注意的是這裡並不對a 的基本的概念作介紹,如果你還對a 演算法不清楚的話,請看姊妹篇 初識a 演算法 這裡所舉的例子是參考amit主頁中的乙個源程式,使用這個源程式時,應該遵守一定的公約。二 a ...