一礁阁、函數(shù)作用域
1、作用域分四種情況:
- L:local族奢,局部作用域姥闭,即函數(shù)中定義的變量
- E:enclosing,嵌套作用域越走,即包含此函數(shù)的上級函數(shù)的局部作用域棚品,但不是全局的靠欢。
- G:global,全局作用域(全局變量)铜跑,就是模塊級別定義的變量门怪,在函數(shù)中可以理解為函數(shù)外面的變量。
- B:built-in锅纺,系統(tǒng)固定模塊里面的變量掷空,比如int等。
搜索變量的優(yōu)先級順序依次是:作用域局部>外層作用域>當(dāng)前模塊中的全局>python內(nèi)置作用域囤锉,也就是LEGB坦弟。
x = str(100)
print('hello' + x)#hello100
# str = 90 #built-in作用域
# print(str)#str內(nèi)置函數(shù)被破壞,絕對不要這樣做
1官地、
g_counter = 33 #全局作用域
# o_count = 77
def outer():
o_count = 0#嵌套作用域
# g_counter = 334
def inner():
i_counter = 5 #局部作用域
o_count = 90
print(i_counter)# inner()
print('out' + str(o_count))#out90
print(o_count)#90
2酿傍、
g_counter = 33
# o_count = 77
def outer():
o_count = 0
# g_counter = 334
def inner():
i_counter = 5
o_count = 90
print('before inner')
print(o_count)#0
inner()
print('after inner')
print(o_count)#0
#局部作用域,超出函數(shù)變量銷毀驱入,所以返回值為最初變量值赤炒。
outer()
2、作用域產(chǎn)生
- 在Python中亏较,只有模塊(module)莺褒,類(class)以及函數(shù)(def、lambda)才會引入新的作用域宴杀,其它的代碼塊(如if癣朗、try、for等)是不會引入新的作用域的旺罢,如下代碼:
if 2 > 1:
x = 3
print(x)#1
這個(gè)是沒有問題的旷余,if并沒有引入一個(gè)新的作用域,x仍處在當(dāng)前作用域中扁达,后面代碼可以使用正卧。
def fun():
x = 3
print(x)# NameError: name 'x2' is not defined
def、class跪解、lambda是可以引入新作用域的炉旷。
3、變量的修改
x = 90
def f2():
print(x)
x = 88
print(x)
f2()
print(x)
# 錯誤的原因在于print(x)時(shí),解釋器會在局部作用域找,會找到x=5(函數(shù)已經(jīng)加載到內(nèi)存),但x使用在聲明前了,所以報(bào)錯:
# local variable 'x' referenced before assignment.如何證明找到了x=5呢?簡單:注釋掉x=5,x=6
# 報(bào)錯為:name 'x' is not defined
#同理
x=6
def f2():
x+=1 #local variable 'x' referenced before assignment.
f2()
4叉讥、global關(guān)鍵字
- 當(dāng)內(nèi)部作用域想修改外部作用域的變量時(shí)窘行,就要用到global和nonlocal關(guān)鍵字了,當(dāng)修改的變量是在全局作用域(global作用域)上的图仓,就要使用global先聲明一下罐盔,代碼如下:
out_count = 3
def outer():
global count
out_count+=3
print(out_count)#6
outer()
5、 nonlocal關(guān)鍵字
- global關(guān)鍵字聲明的變量必須在全局作用域上救崔,不能嵌套作用域上惶看,當(dāng)要修改嵌套作用域(enclosing作用域捏顺,外層非全局作用域)中的變量怎么辦呢,這時(shí)就需要nonlocal關(guān)鍵字了
def outer():
out_count = 3
def inner():
nonlocal out_count
out_count+=3
inner()
print(out_count)#6
6纬黎、小結(jié)
(1)變量查找順序:LEGB幅骄,作用域局部>外層作用域>當(dāng)前模塊中的全局>python內(nèi)置作用域;
(2)只有模塊本今、類拆座、及函數(shù)才能引入新作用域;
(3)對于一個(gè)變量诈泼,內(nèi)部作用域先聲明就會覆蓋外部變量懂拾,不聲明直接使用煤禽,就會使用外部作用域的變量铐达;
(4)內(nèi)部作用域要修改外部作用域變量的值時(shí),全局變量要使用global關(guān)鍵字檬果,嵌套作用域變量要使用nonlocal關(guān)鍵字瓮孙。nonlocal是python3新增的關(guān)鍵字,有了這個(gè) 關(guān)鍵字选脊,就能完美的實(shí)現(xiàn)閉包了杭抠。
二、遞歸函數(shù)
定義:在函數(shù)內(nèi)部恳啥,可以調(diào)用其他函數(shù)偏灿。如果一個(gè)函數(shù)在內(nèi)部調(diào)用自身本身,這個(gè)函數(shù)就是遞歸函數(shù)钝的。
2.1翁垂、階乘
#求n的階乘
def jiecheng_new(n):
if n == 1:
return 1
return n * jiecheng_new(n - 1)
result = jiecheng_new(6)
print(result)#720
2.2、斐波那契數(shù)列
# 0 1 1 2 3 5 8 13 21 34
# 1 1 2 3 5 8 13 21 34
def fibo(n):
before = 0
after = 1
for i in range(n-1):
ret = before + after
before = after
after = ret
print(before,end='\t')
return ret
print(fibo(9))#1 1 2 3 5 8 13 21 34
def fibo(n):
if n<=1:
return n
return(fibo(n-1)+fibo(n-2))
print(fibo(8))#21
- 避免重復(fù)計(jì)算硝桩,加速
cache = {}
def fibo(n):
if n <= 1:
return n
if (n - 1) not in cache:
cache[n-1] = fibo(n-1)
if (n - 2) not in cache:
cache[n-2] = fibo(n-2)
return cache[n-1] + cache[n-2]
print(fibo(100))
- 遞歸函數(shù)的優(yōu)點(diǎn): 是定義簡單沿猜,邏輯清晰。理論上碗脊,所有的遞歸函數(shù)都可以寫成循環(huán)的方式啼肩,但循環(huán)的邏輯不如遞歸清晰。
2.3衙伶、遞歸特性:
(1)必須有一個(gè)明確的結(jié)束條件
(2)每次進(jìn)入更深一層遞歸時(shí)祈坠,問題規(guī)模相比上次遞歸都應(yīng)有所減少
(3)遞歸效率不高,遞歸層次過多會導(dǎo)致棧溢出(在計(jì)算機(jī)中矢劲,函數(shù)調(diào)用是通過棧(stack)這種數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn)的赦拘,每當(dāng)進(jìn)入一個(gè)函數(shù)調(diào)用,棧就會加一層棧幀卧须,每當(dāng)函數(shù)返 回另绩,棧就會減一層棧幀儒陨。由于棧的大小不是無限的,所以笋籽,遞歸調(diào)用的次數(shù)過多蹦漠,會導(dǎo)致棧溢出。) - 練習(xí):水仙花车海,一個(gè)三位數(shù)笛园,它的每個(gè)位上的數(shù)字的3次冪之和等于它本身
flowers = []
def flower():
# 569 // 10
for i in range(100,1000):
baiwei = i // 100
gewei = i % 10
shiwei = (i // 10) % 10
if gewei*gewei*gewei + shiwei*shiwei*shiwei + baiwei*baiwei*baiwei == i:
flowers.append(i)
flower()
print(flowers)#[153, 370, 371, 407]
三、將函數(shù)存儲在模塊中
3.1侍芝、導(dǎo)入整個(gè)模塊
import fibo
#調(diào)用時(shí)
print(fibo.fibo)
3.2研铆、導(dǎo)入特定的函數(shù)
from fibo import fibo
#調(diào)用時(shí)
print(fibo)
3.3、使用as給函數(shù)指定別名
import fibo as fb
from fibo import fibo as fb
3.4州叠、導(dǎo)入模塊中的所有函數(shù)
from fibo import *
四棵红、函數(shù)文檔字符串
函數(shù)文檔字符串documentation string (docstring)是在函數(shù)開頭,用來解釋其接口的字符串咧栗。簡而言之:幫助文檔
- 查看方式
在交互模式下可以使用help查看函數(shù)逆甜,幫助文檔,該界面會跳到幫助界面致板,需要輸入q退出界面
使用doc屬性查看交煞,該方法的幫助文檔文字直接顯示在交互界面上。 代碼如下:
def test(msg):
"""
函數(shù)名:test
功能:測試
參數(shù):無
返回值:無
"""
print("函數(shù)輸出成功"+msg)
test('hello')
print( help(test))
print(test.__doc__)