Python之路Python全域性變數與區域性變數、函式多層巢狀、函式遞迴 Python之路Python全域性變數與區域性變數、函式多層巢狀、函式遞迴
Python之路Python全域性變數與區域性變數、函式多層巢狀、函式遞迴
一、區域性變數與全域性變數
1、在子程式中定義的變數稱為區域性變數,在程式的一開始定義的變數稱為全域性變數。全域性變數作用域是整個程式,區域性變數作用域是定義該變數的子程式。
全域性變數沒有任何縮排,在任何位置都可以呼叫。
子程式:如用def定義的函式。
作用域
一個識別符號的可見範圍,這就是識別符號的作用域。一般常說的是變數的作用域
全域性作用域(global):在整個程式執行環境中都可見
區域性作用域:在函式、類等內部可見;區域性變數使用範圍不能超過其所在的區域性作用域。
例子
NAME = "nicholas"
def change_NAME():
print("change_NAME", NAME)
change_NAME()
print(NAME)
輸出結果
change_NAME nicholas
nicholas
分析:NAME = "nicholas"就是全域性變數,在
change_NAME()函式體內可以直接呼叫打印出“change_NAME nicholas”
2、當全域性變數與區域性變數同名時:
在定義區域性變數的子程式內,區域性變數起作用;在其它地方全域性變數起作用。
例子:
NAME = "nicholas"
def change_NAME():
NAME = "niubi"
print("change_NAME", NAME)
change_NAME()
print(NAME)
輸出結果
change_NAME niubi
nicholas
分析:當全域性變數與區域性變數同名時:在 def change_NAME():函式內部,
執行print("change_NAME", NAME)語句時,這裡的NAME優先呼叫函式內部的值,函式執行結束後執行print(NAME)語句,全域性變數NAME = "nicholas"起作用。
3、如果函式內部無global關鍵字
優先讀取區域性變數,如果沒有區域性變數則讀取全域性變數,此時無法對全域性變數進行賦值。
但是對於可變物件可以對內部元素進行操作(如append()pop()).
大前提:無global關鍵字
a、有宣告(同名)區域性變數
例子
name = ["pony","jack"]
print(1,name)
def change_name():
name = "nicholas"
print("change_name", name)
change_name()
print(2,name)
輸出結果
1 ['pony', 'jack']
change_name nicholas
2 ['pony', 'jack']
1 ['pony', 'jack']
change_name nicholas
2 ['pony', 'jack']
分析:這裡無golbal關鍵字,執行 print(1,name)語句時讀取全域性變數name = ["pony","jack"],之後執行change_name()函式,在函式裡面nema被賦值為"nicholas"
執行print("change_name", name)語句,這裡的name優先讀取函式內部的區域性變數name = "nicholas"
輸出change_name nicholas。之後change_name()函式結束。
執行print(2,name)語句。這裡仍然讀取全域性變數name = ["pony","jack"]。
b、無宣告(同名)區域性變數
例子
name = ["pony","jack"]
print(1,name)
def change_name():
print(3, name)
name.append("nicholas")
print(4,name)
change_name()
print(2,name)
輸出結果
1 ['pony', 'jack']
3 ['pony', 'jack']
4 ['pony', 'jack', 'nicholas']
2 ['pony', 'jack', 'nicholas']
分析:無global關鍵字,針對全域性變數如果是可變物件,可以對內部元素進行操作。
4、如果函式中有global關鍵字,變數本質上就是全域性變數,可讀取可賦值。
a、有宣告(同名)區域性變數
例子
NAME = "nicholas"
print(1,NAME)
def change_NAME():
global NAME
NAME = "niubi"
print("change_NAME", NAME)
change_NAME()
print(2,NAME)
輸出結果
1 nicholas
change_NAME niubi
2 niubi
分析:在執行print("1",NAME)語句時,NAME使用全域性變數,然後執行change_NAME()函式,在函式內部有global關鍵詞宣告,之後執行NAME = "niubi",執行完這句之後整個程式的NAME變數的值就被修改為"niubi"。
繼續輸出change_NAME niubi,函式結束。
最後執行print("2",NAME)語句,由於NAME在函式內部被修改為"niubi",所以這裡輸出
2 niubi
例子2
name = ["pony","jack"]
print(1,name)
def change_name():
global name
name = ["nick"]
name.append("nicholas")
print(3,name)
change_name()
print(2,name)
輸出結果
1 ['pony', 'jack']
3 ['nick', 'nicholas']
2 ['nick', 'nicholas']
分析:
開始name = ["pony","jack"]是全域性變數,之後執行change_name()函式嗎,在函式中有global關鍵字,之後針對name做的修改都相當於將name作為全域性變數來修改。
c、注意global的位置
錯誤例子
分析:如果需要global對全域性變數進行修改這裡的global不能放在name = "nick"下面。
5、程式碼規範:全域性變數字母全部大寫,區域性變數變數名小寫。
二、多層函式的巢狀和作用域
(1)一定要注意函式要先定義,後使用
例子1
def test1():
print("test1")
def test2():
print("test2")
test1()
test2()
分析:這樣是可以的,先定義函式,再使用函式
錯誤例子
def test1():
print("test1")
test2()
def test2():
print("test2")
test1()
分析:這樣的test2()就無法執行。
(2)在函式內定義的函式 在外面不能用到
例子2
def outer():
def inner():
print('inner')
print('outer')
inner()
outer()
分析:函式有可見範圍,這就是作用域的概念。內部函式不能被外部直接使用。
例子
def foo():
print("foo")
too()
def too():
print("too")
foo()
分析:這裡執行順序是載入def foo():
載入def too():然後再執行foo(),所以這裡不會報錯。
(3)分析多層巢狀函式執行過程及結果
例子
NAME = 'nicholas'
def jack():
name = "jack"
print(name)
def pony():
name = "pony"
print(name)
def charles():
name = 'charles'
print(name)
print(name)
charles()
pony()
print(name)
jack()
輸出結果:
jack
pony
pony
charles
jack
分析:
執行過程如下圖
執行順序:1----2----3----3.1----3.2----3.3----3.4----3.3.1----
3.3.2----3.3.3----3.3.4----3.3.5--3.3.3.1--3.3.3.2----3.5
1 首先執行NAME = 'nicholas'語句,
2 載入def jack():函式到記憶體進行編譯,但不執行
3 呼叫jack()函式,開始執行
3.1 執行name = "jack"語句
3.2 執行print(name)語句,這裡由於沒有global關鍵字,優先讀取區域性變數name = "jack",所以這裡輸出jack
3.3 載入def pony():函式到記憶體進行編譯,但不執行
3.4 呼叫pony():函式,開始執行
3.3.1 執行name = "pony"語句,這裡是一個區域性變數
3.3.2 執行print(name)語句,這裡由於沒有global、nonlocal關鍵字,優先讀取區域性變數name = "pony",所以這裡輸出pony
3.3.3 載入charles():函式到記憶體進行編譯,但不執行
3.3.4 執行print(name)語句,這裡由於沒有global、nonlocal關鍵字,優先讀取同一層級的區域性變數name = "pony",所以這裡輸出pony
3.3.5 呼叫charles():函式,開始執行
3.3.3.1 執行name = 'charles'語句,這裡是個區域性變數
3.3.3.2 執行print(name)語句,優先讀取區域性變數name = "charles",所以這裡輸出charles
~~charles():函式結束
~~pony():函式
3.5 執行執行print(name)語句,優先使用同層級的區域性變數name = "jack",所以這裡輸出jack。
~~整體結束
例子
name = "nicholas"
def outer():
name = "nick"
def inner():
print(name)
print(name)
inner()
outer()
輸出結果
nick
nick
分析:注意這裡的inner()函式內部的print(name)語句,這裡仍然是優先使用outer()函式內部的區域性變數name = "nick",而非全域性變數。
(4)
nonlocal關鍵詞
nonlocal,指定上一級變數,如果沒有就繼續往上直到找到為止
例子
看這個程式,分析輸出過程和結果。
def scope_test():
def do_local():
spam = "local spam"
def do_nonlocal():
nonlocal spam
spam = "nonlocal spam"
def do_global():
global spam
spam = "global spam"
spam = "test spam"
do_local()
print("After local assignment:", spam)
do_nonlocal()
print("After nonlocal assignment:", spam)
do_global()
print("After global assignment:", spam)
scope_test()
print("In global scope:", spam)
輸出結果
After local assignment: test spam
After nonlocal assignment: nonlocal spam
After global assignment: nonlocal spam
In global scope: global spam
分析:
程式執行步驟如圖
從1開始
1--2--2.1--2.2--2.3--2.4--2.5--2.5.1--2.5.2--2.6--2.7--2.7.1--2.7.2--2.8
--2.9--2.9.1--2.9.2--2.10--2.11
下面具體分析下程式執行的過程
1 將def scope_test():函式體作為一個整體載入到記憶體中,但不執行
2 呼叫def scope_test():開始執行
2.1 將def do_local():函式體作為一個整體載入到記憶體中,但不執行
2.2 將def do_nonlocal(): 函式體作為一個整體載入到記憶體中,但不執行
2.3 將 def do_global(): 函式體作為一個整體載入到記憶體中,但不執行
2.4 執行 spam = "test spam"
2.5 呼叫 def do_local():函式
2.5.1 執行 def do_local():函式
2.5.2 執行 spam = "local spam"
--完成2.5.2之後 def do_local():函式結束,其所佔的記憶體被回收, spam =
"local spam"資料被銷燬
2.6 執行print("After local assignment:", spam)語句
由於沒有global關鍵字,這裡優先讀取區域性變數,即spam = "test spam"
打印出After local assignment: test spam
2.7 呼叫do_nonlocal()函式
2.7.1 執行def do_nonlocal():
遇到 nonlocal 宣告,nonlocal關鍵字用來在函式外層(非全域性)變數。
這裡的外層即為def scope_test():這個作用域內
2.7.2 執行spam = "nonlocal spam"語句
這時def scope_test():這個作用域內由以前的spam = "test spam"被重新覆蓋為
spam = "nonlocal spam"
--do_nonlocal()函式體結束
2.8 執行 print("After nonlocal assignment:", spam)語句
由於spam被重新賦值為"nonlocal spam",這裡輸出
After nonlocal assignment: nonlocal spam
2.9 呼叫do_global()函式
2.9.1 執行def do_global(): 函式
2.9.2 執行 spam = "global spam" 語句
遇到global宣告,global關鍵字用來在函式整體作用域使用全域性變數。類似於在
def scope_test():上面寫了一句spam = "global spam"
--def do_global(): 函式體結束
2.10 執行print("After global assignment:", spam)語句
由於這一層級作用域沒有global關鍵字,這裡優先讀取區域性變數,即被修改過一次的
spam = "nonlocal spam"
這裡輸出After global assignment: nonlocal spam
2.11執行print("In global scope:", spam)語句
由於在2.9.2 spam被聲明瞭全域性變數,即spam = "global spam"
所以這裡輸出
In global scope: global spam
例子2
name = "jack"
def foo():
name = "nick"
print(name)
def too():
nonlocal name
name = "nicholas"
print(1,name)
too()
print(name)
foo()
輸出結果
nick
1 nicholas
nicholas
分析:注意這裡的def too():函式內print(1,name)語句仍然優先讀取區域性變數name = "nicholas"。
三、遞迴
1、遞迴的定義
如果在呼叫一個函式的過程中直接或間接呼叫自身本身,那麼這種方法叫做遞迴。
2、遞迴的特點
a、遞迴必須有一個明確的結束條件(基例)。
b、每次進入更深一層遞迴時,問題規模相比上次遞迴都應有所減少。
c、遞迴效率不高,遞迴層次過多會導致棧溢位。
3、遞迴的執行過程
例子
def calc(n):
print(n)
if int(n/2) ==0:
return n
return calc(int(n/2))
calc(10)
輸出結果
10
5
2
1
分析執行過程:
具體過程
(1)執行def calc(n):語句,將calc(n)函式載入到記憶體中進行編譯,但不執行
(2)執行calc(10)語句,呼叫calc(n)函式,將n = 10 傳入calc(n)函式
(3)執行print(n)語句,此時n = 10,列印10
判斷n/2是否等於0,10/2 = 5不等於0
執行retun語句,return呼叫calc(n)函式,
此時具體是執行calc(int(10/2))即calc(5)
此層函式暫停,等待calc(5)返回值
(4)執行print(n)語句,此時n = 5,列印5
判斷n/2是否等於0,5/2 = 2不等於0
執行retun語句,return呼叫calc(n)函式,
此時具體是執行calc(int(5/2))即calc(2)
此層函式暫停,等待calc(2)返回值
(5)執行print(n)語句,此時n = 2,列印2
判斷n/2是否等於0,2/2 = 1不等於0
執行retun語句,return呼叫calc(n)函式,
此時具體是執行calc(int(2/2))即calc(1)
此層函式暫停,等待calc(1)返回值
(6)執行print(n)語句,此時n = 1,列印1
判斷n/2是否等於0,1/2 = 2等於0,
執行if條件下的retun語句,return n 給上一層函式,
即return 1給上層函式
(7)將1傳給calc(1),calc(1)得到值為1 ,
return calc(1)即return 1,再次將1傳給上層的return calc(2),
calc(2)得到值為1,再次將1傳給上層的return calc(5),
calc(5)得到值為1,最後將1傳給calc(10),
即calc(10)= 1。
這裡可以列印下calc(10)的值
def calc(n):
print(n)
if int(n / 2) == 0:
return n
return calc(int(n / 2))
v = calc(10)
print("calc(10)是",v)
輸出結果
10
5
2
1
calc(10)是 1
例子2
import time
person_list=['Pony','Charles','Richard ','Jack']
print("How can I make good money?")
def ask(person_list):
print('-'*60)
if len(person_list) == 0:
return "I don't know"
person=person_list.pop(0)
if person == "Jack":
return "%s say:Better have a dream, in case it comes true someday." %person
print('hi Boss[%s],How can I make good money?' %person)
print("%s replied:I don't know,But I konw you are a smart boy,hold on ,I can help you ask %s..." %(person,person_list))
time.sleep(10)
res=ask(person_list)
#print('%s say: %res' %(person,res))#註釋語句
return res
res = ask(person_list)
print(res)
輸出結果
How can I make good money?
------------------------------------------------------------
hi Boss[Pony],How can I make good money?
Pony replied:I don't know,But I konw you are a smart boy,hold on ,I can help you ask ['Charles', 'Richard ', 'Jack']...
------------------------------------------------------------
hi Boss[Charles],How can I make good money?
Charles replied:I don't know,But I konw you are a smart boy,hold on ,I can help you ask ['Richard ', 'Jack']...
------------------------------------------------------------
hi Boss[Richard ],How can I make good money?
Richard replied:I don't know,But I konw you are a smart boy,hold on ,I can help you ask ['Jack']...
------------------------------------------------------------
Jack say:Better have a dream, in case it comes true someday.
如果取消上面print('%s say: %res' %(person,res))註釋,執行這一語句,可以看出return返回的過程
如下
import time
person_list=['Pony','Charles','Richard ','Jack']
print("How can I make good money?")
def ask(person_list):
print('-'*60)
if len(person_list) == 0:
return "I don't know"
person=person_list.pop(0)
if person == "Jack":
return "%s say:Better have a dream, in case it comes true someday." %person
print('hi Boss[%s],How can I make good money?' %person)
print("%s replied:I don't know,But I konw you are a smart boy,hold on ,I can help you ask %s..." %(person,person_list))
time.sleep(1)
res=ask(person_list)#第一處
print('%s say: %res' %(person,res))
return res
res = ask(person_list)#第二處
print(res)
輸出結果
How can I make good money?
------------------------------------------------------------
hi Boss[Pony],How can I make good money?
Pony replied:I don't know,But I konw you are a smart boy,hold on ,I can help you ask ['Charles', 'Richard ', 'Jack']...
------------------------------------------------------------
hi Boss[Charles],How can I make good money?
Charles replied:I don't know,But I konw you are a smart boy,hold on ,I can help you ask ['Richard ', 'Jack']...
------------------------------------------------------------
hi Boss[Richard ],How can I make good money?
Richard replied:I don't know,But I konw you are a smart boy,hold on ,I can help you ask ['Jack']...
------------------------------------------------------------
Richard say: 'Jack say:Better have a dream, in case it comes true someday.'es
Charles say: 'Jack say:Better have a dream, in case it comes true someday.'es
Pony say: 'Jack say:Better have a dream, in case it comes true someday.'es
Jack say:Better have a dream, in case it comes true someday.
分析:最後的返回結果是Richard返回給Charles,Charles返回給Pony
第一處的res=ask(person_list) 就算執行完了,res得到Jack say:Better have a dream, in case it comes true someday.
然後return給函式外的res,最後列印這句話。
一、區域性變數與全域性變數
1、在子程式中定義的變數稱為區域性變數,在程式的一開始定義的變數稱為全域性變數。全域性變數作用域是整個程式,區域性變數作用域是定義該變數的子程式。
全域性變數沒有任何縮排,在任何位置都可以呼叫。
子程式:如用def定義的函式。
作用域
一個識別符號的可見範圍,這就是識別符號的作用域。一般常說的是變數的作用域
全域性作用域(global):在整個程式執行環境中都可見
區域性作用域:在函式、類等內部可見;區域性變數使用範圍不能超過其所在的區域性作用域。
例子
NAME = "nicholas"
def change_NAME():
print("change_NAME", NAME)
change_NAME()
print(NAME)
輸出結果
change_NAME nicholas
nicholas
分析:NAME = "nicholas"就是全域性變數,在
change_NAME()函式體內可以直接呼叫打印出“change_NAME nicholas”
2、當全域性變數與區域性變數同名時:
在定義區域性變數的子程式內,區域性變數起作用;在其它地方全域性變數起作用。
例子:
NAME = "nicholas"
def change_NAME():
NAME = "niubi"
print("change_NAME", NAME)
change_NAME()
print(NAME)
輸出結果
change_NAME niubi
nicholas
分析:當全域性變數與區域性變數同名時:在 def change_NAME():函式內部,
執行print("change_NAME", NAME)語句時,這裡的NAME優先呼叫函式內部的值,函式執行結束後執行print(NAME)語句,全域性變數NAME = "nicholas"起作用。
3、如果函式內部無global關鍵字
優先讀取區域性變數,如果沒有區域性變數則讀取全域性變數,此時無法對全域性變數進行賦值。
但是對於可變物件可以對內部元素進行操作(如append()pop()).
大前提:無global關鍵字
a、有宣告(同名)區域性變數
例子
name = ["pony","jack"]
print(1,name)
def change_name():
name = "nicholas"
print("change_name", name)
change_name()
print(2,name)
輸出結果
1 ['pony', 'jack']
change_name nicholas
2 ['pony', 'jack']
1 ['pony', 'jack']
change_name nicholas
2 ['pony', 'jack']
分析:這裡無golbal關鍵字,執行 print(1,name)語句時讀取全域性變數name = ["pony","jack"],之後執行change_name()函式,在函式裡面nema被賦值為"nicholas"
執行print("change_name", name)語句,這裡的name優先讀取函式內部的區域性變數name = "nicholas"
輸出change_name nicholas。之後change_name()函式結束。
執行print(2,name)語句。這裡仍然讀取全域性變數name = ["pony","jack"]。
b、無宣告(同名)區域性變數
例子
name = ["pony","jack"]
print(1,name)
def change_name():
print(3, name)
name.append("nicholas")
print(4,name)
change_name()
print(2,name)
輸出結果
1 ['pony', 'jack']
3 ['pony', 'jack']
4 ['pony', 'jack', 'nicholas']
2 ['pony', 'jack', 'nicholas']
分析:無global關鍵字,針對全域性變數如果是可變物件,可以對內部元素進行操作。
4、如果函式中有global關鍵字,變數本質上就是全域性變數,可讀取可賦值。
a、有宣告(同名)區域性變數
例子
NAME = "nicholas"
print(1,NAME)
def change_NAME():
global NAME
NAME = "niubi"
print("change_NAME", NAME)
change_NAME()
print(2,NAME)
輸出結果
1 nicholas
change_NAME niubi
2 niubi
分析:在執行print("1",NAME)語句時,NAME使用全域性變數,然後執行change_NAME()函式,在函式內部有global關鍵詞宣告,之後執行NAME = "niubi",執行完這句之後整個程式的NAME變數的值就被修改為"niubi"。
繼續輸出change_NAME niubi,函式結束。
最後執行print("2",NAME)語句,由於NAME在函式內部被修改為"niubi",所以這裡輸出
2 niubi
例子2
name = ["pony","jack"]
print(1,name)
def change_name():
global name
name = ["nick"]
name.append("nicholas")
print(3,name)
change_name()
print(2,name)
輸出結果
1 ['pony', 'jack']
3 ['nick', 'nicholas']
2 ['nick', 'nicholas']
分析:
開始name = ["pony","jack"]是全域性變數,之後執行change_name()函式嗎,在函式中有global關鍵字,之後針對name做的修改都相當於將name作為全域性變數來修改。
c、注意global的位置
錯誤例子
分析:如果需要global對全域性變數進行修改這裡的global不能放在name = "nick"下面。
5、程式碼規範:全域性變數字母全部大寫,區域性變數變數名小寫。
二、多層函式的巢狀和作用域
(1)一定要注意函式要先定義,後使用
例子1
def test1():
print("test1")
def test2():
print("test2")
test1()
test2()
分析:這樣是可以的,先定義函式,再使用函式
錯誤例子
def test1():
print("test1")
test2()
def test2():
print("test2")
test1()
分析:這樣的test2()就無法執行。
(2)在函式內定義的函式 在外面不能用到
例子2
def outer():
def inner():
print('inner')
print('outer')
inner()
outer()
分析:函式有可見範圍,這就是作用域的概念。內部函式不能被外部直接使用。
例子
def foo():
print("foo")
too()
def too():
print("too")
foo()
分析:這裡執行順序是載入def foo():
載入def too():然後再執行foo(),所以這裡不會報錯。
(3)分析多層巢狀函式執行過程及結果
例子
NAME = 'nicholas'
def jack():
name = "jack"
print(name)
def pony():
name = "pony"
print(name)
def charles():
name = 'charles'
print(name)
print(name)
charles()
pony()
print(name)
jack()
輸出結果:
jack
pony
pony
charles
jack
分析:
執行過程如下圖
執行順序:1----2----3----3.1----3.2----3.3----3.4----3.3.1----
3.3.2----3.3.3----3.3.4----3.3.5--3.3.3.1--3.3.3.2----3.5
1 首先執行NAME = 'nicholas'語句,
2 載入def jack():函式到記憶體進行編譯,但不執行
3 呼叫jack()函式,開始執行
3.1 執行name = "jack"語句
3.2 執行print(name)語句,這裡由於沒有global關鍵字,優先讀取區域性變數name = "jack",所以這裡輸出jack
3.3 載入def pony():函式到記憶體進行編譯,但不執行
3.4 呼叫pony():函式,開始執行
3.3.1 執行name = "pony"語句,這裡是一個區域性變數
3.3.2 執行print(name)語句,這裡由於沒有global、nonlocal關鍵字,優先讀取區域性變數name = "pony",所以這裡輸出pony
3.3.3 載入charles():函式到記憶體進行編譯,但不執行
3.3.4 執行print(name)語句,這裡由於沒有global、nonlocal關鍵字,優先讀取同一層級的區域性變數name = "pony",所以這裡輸出pony
3.3.5 呼叫charles():函式,開始執行
3.3.3.1 執行name = 'charles'語句,這裡是個區域性變數
3.3.3.2 執行print(name)語句,優先讀取區域性變數name = "charles",所以這裡輸出charles
~~charles():函式結束
~~pony():函式
3.5 執行執行print(name)語句,優先使用同層級的區域性變數name = "jack",所以這裡輸出jack。
~~整體結束
例子
name = "nicholas"
def outer():
name = "nick"
def inner():
print(name)
print(name)
inner()
outer()
輸出結果
nick
nick
分析:注意這裡的inner()函式內部的print(name)語句,這裡仍然是優先使用outer()函式內部的區域性變數name = "nick",而非全域性變數。
(4)
nonlocal關鍵詞
nonlocal,指定上一級變數,如果沒有就繼續往上直到找到為止
例子
看這個程式,分析輸出過程和結果。
def scope_test():
def do_local():
spam = "local spam"
def do_nonlocal():
nonlocal spam
spam = "nonlocal spam"
def do_global():
global spam
spam = "global spam"
spam = "test spam"
do_local()
print("After local assignment:", spam)
do_nonlocal()
print("After nonlocal assignment:", spam)
do_global()
print("After global assignment:", spam)
scope_test()
print("In global scope:", spam)
輸出結果
After local assignment: test spam
After nonlocal assignment: nonlocal spam
After global assignment: nonlocal spam
In global scope: global spam
分析:
程式執行步驟如圖
從1開始
1--2--2.1--2.2--2.3--2.4--2.5--2.5.1--2.5.2--2.6--2.7--2.7.1--2.7.2--2.8
--2.9--2.9.1--2.9.2--2.10--2.11
下面具體分析下程式執行的過程
1 將def scope_test():函式體作為一個整體載入到記憶體中,但不執行
2 呼叫def scope_test():開始執行
2.1 將def do_local():函式體作為一個整體載入到記憶體中,但不執行
2.2 將def do_nonlocal(): 函式體作為一個整體載入到記憶體中,但不執行
2.3 將 def do_global(): 函式體作為一個整體載入到記憶體中,但不執行
2.4 執行 spam = "test spam"
2.5 呼叫 def do_local():函式
2.5.1 執行 def do_local():函式
2.5.2 執行 spam = "local spam"
--完成2.5.2之後 def do_local():函式結束,其所佔的記憶體被回收, spam =
"local spam"資料被銷燬
2.6 執行print("After local assignment:", spam)語句
由於沒有global關鍵字,這裡優先讀取區域性變數,即spam = "test spam"
打印出After local assignment: test spam
2.7 呼叫do_nonlocal()函式
2.7.1 執行def do_nonlocal():
遇到 nonlocal 宣告,nonlocal關鍵字用來在函式外層(非全域性)變數。
這裡的外層即為def scope_test():這個作用域內
2.7.2 執行spam = "nonlocal spam"語句
這時def scope_test():這個作用域內由以前的spam = "test spam"被重新覆蓋為
spam = "nonlocal spam"
--do_nonlocal()函式體結束
2.8 執行 print("After nonlocal assignment:", spam)語句
由於spam被重新賦值為"nonlocal spam",這裡輸出
After nonlocal assignment: nonlocal spam
2.9 呼叫do_global()函式
2.9.1 執行def do_global(): 函式
2.9.2 執行 spam = "global spam" 語句
遇到global宣告,global關鍵字用來在函式整體作用域使用全域性變數。類似於在
def scope_test():上面寫了一句spam = "global spam"
--def do_global(): 函式體結束
2.10 執行print("After global assignment:", spam)語句
由於這一層級作用域沒有global關鍵字,這裡優先讀取區域性變數,即被修改過一次的
spam = "nonlocal spam"
這裡輸出After global assignment: nonlocal spam
2.11執行print("In global scope:", spam)語句
由於在2.9.2 spam被聲明瞭全域性變數,即spam = "global spam"
所以這裡輸出
In global scope: global spam
例子2
name = "jack"
def foo():
name = "nick"
print(name)
def too():
nonlocal name
name = "nicholas"
print(1,name)
too()
print(name)
foo()
輸出結果
nick
1 nicholas
nicholas
分析:注意這裡的def too():函式內print(1,name)語句仍然優先讀取區域性變數name = "nicholas"。
三、遞迴
1、遞迴的定義
如果在呼叫一個函式的過程中直接或間接呼叫自身本身,那麼這種方法叫做遞迴。
2、遞迴的特點
a、遞迴必須有一個明確的結束條件(基例)。
b、每次進入更深一層遞迴時,問題規模相比上次遞迴都應有所減少。
c、遞迴效率不高,遞迴層次過多會導致棧溢位。
3、遞迴的執行過程
例子
def calc(n):
print(n)
if int(n/2) ==0:
return n
return calc(int(n/2))
calc(10)
輸出結果
10
5
2
1
分析執行過程:
具體過程
(1)執行def calc(n):語句,將calc(n)函式載入到記憶體中進行編譯,但不執行
(2)執行calc(10)語句,呼叫calc(n)函式,將n = 10 傳入calc(n)函式
(3)執行print(n)語句,此時n = 10,列印10
判斷n/2是否等於0,10/2 = 5不等於0
執行retun語句,return呼叫calc(n)函式,
此時具體是執行calc(int(10/2))即calc(5)
此層函式暫停,等待calc(5)返回值
(4)執行print(n)語句,此時n = 5,列印5
判斷n/2是否等於0,5/2 = 2不等於0
執行retun語句,return呼叫calc(n)函式,
此時具體是執行calc(int(5/2))即calc(2)
此層函式暫停,等待calc(2)返回值
(5)執行print(n)語句,此時n = 2,列印2
判斷n/2是否等於0,2/2 = 1不等於0
執行retun語句,return呼叫calc(n)函式,
此時具體是執行calc(int(2/2))即calc(1)
此層函式暫停,等待calc(1)返回值
(6)執行print(n)語句,此時n = 1,列印1
判斷n/2是否等於0,1/2 = 2等於0,
執行if條件下的retun語句,return n 給上一層函式,
即return 1給上層函式
(7)將1傳給calc(1),calc(1)得到值為1 ,
return calc(1)即return 1,再次將1傳給上層的return calc(2),
calc(2)得到值為1,再次將1傳給上層的return calc(5),
calc(5)得到值為1,最後將1傳給calc(10),
即calc(10)= 1。
這裡可以列印下calc(10)的值
def calc(n):
print(n)
if int(n / 2) == 0:
return n
return calc(int(n / 2))
v = calc(10)
print("calc(10)是",v)
輸出結果
10
5
2
1
calc(10)是 1
例子2
import time
person_list=['Pony','Charles','Richard ','Jack']
print("How can I make good money?")
def ask(person_list):
print('-'*60)
if len(person_list) == 0:
return "I don't know"
person=person_list.pop(0)
if person == "Jack":
return "%s say:Better have a dream, in case it comes true someday." %person
print('hi Boss[%s],How can I make good money?' %person)
print("%s replied:I don't know,But I konw you are a smart boy,hold on ,I can help you ask %s..." %(person,person_list))
time.sleep(10)
res=ask(person_list)
#print('%s say: %res' %(person,res))#註釋語句
return res
res = ask(person_list)
print(res)
輸出結果
How can I make good money?
------------------------------------------------------------
hi Boss[Pony],How can I make good money?
Pony replied:I don't know,But I konw you are a smart boy,hold on ,I can help you ask ['Charles', 'Richard ', 'Jack']...
------------------------------------------------------------
hi Boss[Charles],How can I make good money?
Charles replied:I don't know,But I konw you are a smart boy,hold on ,I can help you ask ['Richard ', 'Jack']...
------------------------------------------------------------
hi Boss[Richard ],How can I make good money?
Richard replied:I don't know,But I konw you are a smart boy,hold on ,I can help you ask ['Jack']...
------------------------------------------------------------
Jack say:Better have a dream, in case it comes true someday.
如果取消上面print('%s say: %res' %(person,res))註釋,執行這一語句,可以看出return返回的過程
如下
import time
person_list=['Pony','Charles','Richard ','Jack']
print("How can I make good money?")
def ask(person_list):
print('-'*60)
if len(person_list) == 0:
return "I don't know"
person=person_list.pop(0)
if person == "Jack":
return "%s say:Better have a dream, in case it comes true someday." %person
print('hi Boss[%s],How can I make good money?' %person)
print("%s replied:I don't know,But I konw you are a smart boy,hold on ,I can help you ask %s..." %(person,person_list))
time.sleep(1)
res=ask(person_list)#第一處
print('%s say: %res' %(person,res))
return res
res = ask(person_list)#第二處
print(res)
輸出結果
How can I make good money?
------------------------------------------------------------
hi Boss[Pony],How can I make good money?
Pony replied:I don't know,But I konw you are a smart boy,hold on ,I can help you ask ['Charles', 'Richard