1、局部變量與全局變量python
一、在子程序中定義的變量稱爲局部變量,在程序的一開始定義的變量稱爲全局變量。全局變量做用域是整個程序,局部變量做用域是定義該變量的子程序。app
全局變量沒有任何縮進,在任何位置均可以調用。函數
子程序:如用def定義的函數。spa
做用域3d
一個標識符的可見範圍,這就是標識符的做用域。通常常說的是變量的做用域代碼規範
全局做用域(global):在整個程序運行環境中均可見對象
局部做用域:在函數、類等內部可見;局部變量使用範圍不能超過其所在的局部做用域。blog
例子遞歸
NAME = "nicholas" def change_NAME(): print("change_NAME", NAME) change_NAME() print(NAME)
輸出結果內存
change_NAME nicholas nicholas
分析:NAME = "nicholas"就是全局變量,在
change_NAME()函數體內能夠直接調用打印出「change_NAME nicholas」
二、當全局變量與局部變量同名時:
在定義局部變量的子程序內,局部變量起做用;在其它地方全局變量起做用。
例子:
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"起做用。
三、若是函數內部無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']
分析:這裏無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關鍵字,針對全局變量若是是可變對象,能夠對內部元素進行操做。
四、若是函數中有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的位置
錯誤例子
name = ["pony","jack"] def change_name(): name = "nick" global name name.append("nicholas") change_name() print(name)
分析:若是須要global對全局變量進行修改這裏的global不能放在name = "nick"下面。
五、代碼規範:全局變量字母所有大寫,局部變量變量名小寫。
2、多層函數的嵌套和做用域
(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"。
3、遞歸
一、遞歸的定義
若是在調用一個函數的過程當中直接或間接調用自身自己,那麼這種方法叫作遞歸。
二、遞歸的特色
a、遞歸必須有一個明確的結束條件(基例)。
b、每次進入更深一層遞歸時,問題規模相比上次遞歸都應有所減小。
c、遞歸效率不高,遞歸層次過多會致使棧溢出。
三、遞歸的執行過程
例子
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,最後打印這句話。