大家好,我是老馬的程序人生~
變量作用域是Python定義函數(shù)時(shí)需要考慮的重要問題,在此為大家總結(jié)一下。
「1. 內(nèi)嵌函數(shù)」
Python支持內(nèi)嵌函數(shù)(內(nèi)嵌函數(shù):函數(shù)內(nèi)部又定義一個(gè)完整的函數(shù))。
【例子】
def outer():
print('outer函數(shù)在這被調(diào)用')
def inner():
print('inner函數(shù)在這被調(diào)用')
inner() # 該函數(shù)只能在outer函數(shù)內(nèi)部被調(diào)用
outer()
# outer函數(shù)在這被調(diào)用
# inner函數(shù)在這被調(diào)用
「2. 局部作用域、閉包作用域、全局作用域、內(nèi)置作用域」
【例子】
def foo():
b = 'hello'
# Python中可以在函數(shù)內(nèi)部再定義函數(shù)
def bar():
c = True
print(a)
print(b)
print(c)
bar()
# print(c) # NameError: name 'c' is not defined
a = 100
# print(b) # NameError: name 'b' is not defined
foo()
# 100
# hello
# True
上面的代碼能夠順利的執(zhí)行并且打印出100、hello和True,但我們注意到了,在bar()
函數(shù)的內(nèi)部并沒有定義a
和b
兩個(gè)變量,那么a
和b
是從哪里來的。
我們?cè)谏厦娲a中定義了一個(gè)變量a
,這是一個(gè)全局變量(global variable),屬于全局作用域,因?yàn)樗鼪]有定義在任何一個(gè)函數(shù)中。在上面的foo()
函數(shù)中我們定義了變量b
,這是一個(gè)定義在函數(shù)中的局部變量(local variable),屬于局部作用域,在foo()
函數(shù)的外部并不能訪問到它;但對(duì)于foo()
函數(shù)內(nèi)部的bar()
函數(shù)來說,變量b
屬于閉包作用域,在bar()
函數(shù)中我們是可以訪問到它的。bar()
函數(shù)中的變量c屬于局部作用域,在bar()
函數(shù)之外是無法訪問的。
事實(shí)上,Python查找一個(gè)變量時(shí)會(huì)按照“局部作用域”、“閉包作用域”、“全局作用域”和“內(nèi)置作用域”的順序進(jìn)行搜索,前三者我們?cè)谏厦娴拇a中已經(jīng)看到了,所謂的“內(nèi)置作用域”就是Python內(nèi)置的那些標(biāo)識(shí)符,我們之前用過的input
、print
、int
等都屬于內(nèi)置作用域。
「3. 閉包」
閉包是函數(shù)式編程的一個(gè)重要的語法結(jié)構(gòu),是一種特殊的內(nèi)嵌函數(shù)。
如果在一個(gè)內(nèi)嵌函數(shù)里對(duì)外層非全局作用域的變量進(jìn)行引用,那么內(nèi)部函數(shù)就被認(rèn)為是閉包。
def funX(x):
def funY(y):
return x * y
return funY
i = funX(8)
print(type(i)) # <class 'function'>
print(i(5)) # 40
【例子】閉包的返回值通常是函數(shù)。
def make_counter(init):
counter = [init]
def inc(): counter[0] += 1
def dec(): counter[0] -= 1
def get(): return counter[0]
def reset(): counter[0] = init
return inc, dec, get, reset
inc, dec, get, reset = make_counter(0)
inc()
inc()
inc()
print(get()) # 3
dec()
print(get()) # 2
reset()
print(get()) # 0
「4. global和nonlocal關(guān)鍵字」
再看看下面這段代碼,我們希望通過函數(shù)調(diào)用修改全局變量a
的值,但實(shí)際上下面的代碼是做不到的。
def foo():
a = 200
print(a)
a = 100
foo()
print(a)
# 200
# 100
在調(diào)用foo()
函數(shù)后,我們發(fā)現(xiàn)a
的值仍然是100,這是因?yàn)楫?dāng)我們?cè)诤瘮?shù)foo()
中寫a = 200
的時(shí)候,是重新定義了一個(gè)名字為a
的局部變量,它跟全局作用域的a
并不是同一個(gè)變量,因?yàn)榫植孔饔糜蛑杏辛俗约旱淖兞?code style="overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(145, 109, 213);font-weight: bolder;background-image: none;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;">a,因此foo()
函數(shù)不再搜索全局作用域中的a
。
如果我們希望在foo()
函數(shù)中修改全局作用域中的a
,代碼如下所示。
def foo():
global a
print(a)
a = 200
print(a)
a = 100
foo()
print(a)
# 100
# 200
# 200
我們可以使用global
關(guān)鍵字來指示foo()
函數(shù)中的變量a
來自于全局作用域,如果全局作用域中沒有a
,那么下面一行的代碼就會(huì)定義變量a
并將其置于全局作用域。
同理,如果我們希望函數(shù)內(nèi)部的函數(shù)能夠修改閉包作用域中的變量,可以使用nonlocal
關(guān)鍵字來指示變量來自于閉包作用域。
def outer():
num = 10
def inner():
nonlocal num # nonlocal關(guān)鍵字聲明
num = 100
print(num)
inner()
print(num)
outer()
# 100
# 100
小結(jié):
Python 中,程序的變量并不是在哪個(gè)位置都可以訪問的,訪問權(quán)限決定于這個(gè)變量是在哪里賦值的。
global
關(guān)鍵字nonlocal
關(guān)鍵字聯(lián)系客服