函數內部的函數只能在函數內部調用,不能在函數外部調用,通過接下來的學習你將會知道爲什麼會出現這種情況。
def f1():
def f2():
print('from f2')
f2()
f2() # NameError: name 'f2' is not defined
一、名稱空間
名稱空間(name spaces):在內存管理那一章節時,我們曾說到變量的創建其實就是在內存中開闢了一個新的空間。但是我們一直在迴避變量名的存儲,其實在內存中有一塊內存存儲變量名與變量間的綁定關係的空間,而這個空間稱爲名稱空間。
1 內置名稱空間
內置名稱空間:存放Pyhton解釋器自帶的名字,如int、float、len
生命週期:在解釋器啓動時生效,在解釋器關閉時失效
2 全局名稱空間
全局名稱空間:除了內置和局部的名字之外,其餘都存放在全局名稱空間,如下面代碼中的x、func、l、z
生命週期:在文件執行時生效,在文件執行結束後失效
x = 1
def func():
pass
l = [1, 2]
if 3 > 2:
if 4 > 3:
z = 3
3 局部名稱空間
局部名稱空間:用於存放函數調用期間函數體產生的名字,如下面代碼的f2
生命週期:在文件執行時函數調用期間時生效,在函數執行結束後失效
def f1():
def f2():
print('from f2')
f2()
f1()
4 加載順序
由於.py文件是由Python解釋器打開的,因此一定是在Python解釋器中的內置名稱空間加載結束後,文件纔開始打開,這個時候纔會產生全局名稱空間,但文件內有某一個函數被調用的時候,纔會開始產生局部名稱空間,因此名稱空間的加載順序爲:內置--》全局--》局部。
5 查找順序
由於名稱空間是用來存放變量名與值之間的綁定關係的,所以但凡要查找名字,一定是從三者之一找到,查找順序爲:
從當前的所在位置開始查找,如果當前所在的位置爲局部名稱空間,則查找順序爲:局部--》全局--》內置。
x = 1
y = 2
len = 100
def func():
y = 3
len = 1000
print(f"y: {y}")
print(f"len: {len}")
# print(a) # NameError: name 'a' is not defined
func()
輸出
y: 3
len: 1000
x = 1
def func():
print(x)
x = 10
func()
輸出
10
二、作用域
域指的是區域,作用域即作用的區域。
1 全局作用域
全局作用域:全局有效,全局存活,包含內置名稱空間和全局名稱空間。
# 全局作用域
x = 1
def bar():
print(x)
bar()
輸出
1
2 局部作用域
局部作用域:局部有小,臨時存儲,只包含局部名稱空間。
# 局部作用域
def f1():
def f2():
def f3():
print(x)
x = 2
f3()
f2()
f1()
輸出
2
3 注意點
需要注意的是:作用域關係在函數定義階段就固定死了,與函數的調用無關。
# 作用域注意點
x = 1
def f1(): # 定義階段x=1
print(x)
def f2():
x = 2
f1()
f2()
輸出
1
4 函數對象+作用域應用
# 作用域應用
def f1():
def inner():
print('from inner')
return inner
f = f1() # 把局部定義的函數放在全局之中
def bar():
f()
bar()
輸出
from inner
三、補充知識點
1 global關鍵字
修改全局作用域中的變量。
x = 1
def f1():
x = 2
def f2():
# global x # 修改全局
x = 3
f2()
f1()
print(x)
輸出
1
x = 1
def f1():
x = 2
def f2():
global x # 修改全局
x = 3
f2()
f1()
print(x)
輸出
3
2 nonlocal關鍵字
修改局部作用域中的變量。
x = 1
def f1():
x = 2
def f2():
# nonlocal x
x = 3
f2()
print(x)
#學習中遇到問題沒人解答?小編創建了一個Python學習交流羣:711312441
f1()
輸出
2
x = 1
def f1():
x = 2
def f2():
nonlocal x
x = 3
f2()
print(x)
f1()
輸出
3
3 注意點
在局部想要修改全局的可變類型,不需要任何聲明,可以直接修改。
在局部如果想要修改全局的不可變類型,需要藉助global聲明,聲明爲全局的變量,即可直接修改。
lis = []
def f1():
lis.append(1)
print(f"調用函數前: {lis}")
f1()
print(f"調用函數後: {lis}")
輸出
調用函數前: []
調用函數後: [1]