一、函數之名稱空間
1.1、什麼是名稱空間
名稱空間:存放名字的地方
例子:S=1,1存放於內存中,那名字 S 存放在哪裏呢?名稱空間正是存放名字x與1綁定關係的地方
1.2、名稱空間 (存放名字與值的綁定關係)
1、內置名稱空間
存放python解釋器自帶名字,比如內置的函數名:len,max,sum
創建:隨着python解釋器啓動而創建
銷燬:隨着python解釋器關閉而銷燬
2、全局名稱空間
存放文件級別的名字,比如x,f1,z
x=1
def f1():
y=2
if x == 1:
z=3
創建:文件開始執行時則立即創建
銷燬:文件開始執行完畢時則銷燬
3、局部名稱空間
存放函數內的名字,強調:函數的參數也屬於局部的
創建:函數執行時才臨時創建
銷燬:函數執行完畢則立即銷燬
4、名稱空間的加載順序
內置名稱空間--->全局名稱空間--->局部名稱空間
強調:加載的目的是爲了把名字存起來,存起來的目的是爲了取出來,那麼但凡查找一個名字一定會從三種名稱空間之一找到。
5、名稱空間的查找名字順序
局部名稱空間===>全局名稱空間===>內置名稱空間
例子:名稱空間加載順序與名稱空間查找名字順序使用案例:
len=10
def f1():
# len=100
def f2():
# len=1000
def f3():
# len=10000
print(len)
f3()
# len=200
f2()
len=11111111111 #這裏相當於修改了全局定義的'len=10',修改爲'len=11111111111'
f1()
len=11111111111
函數的查找關係是在函數定義階段就已經固定死的,與調用位置無關
# 函數名字的查找關係是在函數定義階段就已經固定死的,與調用位置無關
x=100
def f1():
x=10
print(x)
def f2():
x=111111
f1()
f2()
>>:10
二、作用域
全局範圍:內置名稱空間中的名字,全局名稱空間中的名字
特點:全局有效,全局存活
局部範圍:局部名稱空間中的名字
特點:局部有效,臨時存活
全局變量:定義在全局作用域的名字
局部變量:定義在局部作用域的名字
2.1、當全局數據類型是可變類型時,在函數內是可以修改的
l=[] #全局類型(可變數據類型)
def foo1():
l.append(2) #在函數內往全局類型裏面追加數據
foo1()
print(l)
>>:[2] #追加完畢後,全局類型l的值已經爲[2]
2.2、當全局數據類型是不可變類型時,在函數內不能修改
L=100 #全局類型(不可變類型)
def foo1():
L=222 #在函數內定義L的值爲222
foo1()
print(L)
>>:100 #執行後全局類型L的值並沒有被修改
2.3、global與nonlocal
1、global用法(改全局變量的值):如果全局數據類型是不可變類型時,在函數內想要修改該變量的值的話。(global這種方式最好少用,因爲改全局變量的值後,其他代碼調用這個全局變量時也會修改)
L=100 #全局類型(不可變類型)
def foo1():
global L #使用global則聲明:L爲全局類型
L=222 #在函數內定義L的值爲222
foo1()
print(L)
>>:222 #執行後全局類型L的值就被修改爲222
2、nonlocal用法(修改當前上一層變量的值,如果沒有則報錯):nonlocal會從當前外一層開始查找,一直查找到最外層的函數,如果沒有找到則報錯
def foo1():
x=10
def foo2():
nonlocal x #使用nonlocal則聲明:x是當前函數外層的變量
x=100
foo2()
print(x) #在此處打印函數foo1內x的值
foo1()
>>:100
三、函數對象
函數對象:函數可以當做變量去處理 (把函數想想成一個變量) ,那麼:
1、函數可以被賦值
def foo():
print('from foo')
f = foo
print(foo)
print(f)
foo()
f()
>>:<function foo at 0x000002401456AC80> #這是執行print(foo) 得到的
>>:<function foo at 0x000002401456AC80> #這是執行print(f) 得到的
>>:from foo #這是執行foo() 得到的
>>:from foo #這是執行f() 得到的
2、函數可以當做參數傳給一個函數
def foo():
print('from foo')
print(foo)
def bar(func): # func=foo
print(func)
func()
bar(foo) #執行函數bar時傳參數爲"foo(foo爲函數),那麼func接收到的值就爲函數'foo'"
>>:<function foo at 0x000002B418DFAD08> #這是執行print(func) 得到的
>>:from foo #這是執行func() 得到的,運行func()就相當於運行了foo()
>>:<function foo at 0x000002B418DFAD08> #這是執行print(foo)得到的
3、可以當做函數的返回值
def bar():
print('from bar')
def foo(func): # func=bar
return func # return bar
f=foo(bar)
此時:f就等於函數bar,它們內存地址都是一樣的
print(f)
得到的值:<function bar at 0x000001DE62D23E18>
print(bar)
得到的值:<function bar at 0x000001DE62D23E18>
那麼執行f()就相當於執行函數bar()
f()
得到的值:from bar
bar()
得到的值:from bar
4、可以當做容器類型元素 (這個功能常常用到)
def get():
print('from get')
def put():
print('from put')
def ls():
print('from ls')
def login():
print('from login')
main_dict={
'1':[get,'下載'],
'2':[put,'上傳'],
'3':[ls,'查看'],
'4':[login,'登錄'],
}
def run():
while True:
print("----------------------")
for n in main_dict:
print(n,main_dict[n][1])
print('輸入 "q" 或者 "exit" 即可退出程序!')
print("----------------------")
choose=input('pls input num:> ').strip()
if len(choose) == 0:continue
if choose == 'q' or choose == 'exit':break
if choose in main_dict:
main_dict[choose][0]()
run()
四、閉包函數 == [函數嵌套+名稱空間與作用域+函數對象] 三者的綜合應用
1、什麼是閉包函數?
1.定義在函數內的函數。
2.該函數體代碼包含對該函數外層作用域中名字的引用 ,強調:函數外層指的不是全局作用域(而是函數內部的)。
滿足上述兩個條件,那麼該內部函數就稱之爲閉包函數。
閉包指的是一個概念,總結了:函數的作用域關係是在函數定義階段就已經固定死的,與調用位置無關。
閉包:閉的概念指的是,這個函數一定是來自於函數內的。
包的概念指的是,這個res函數拿到的不僅僅是函數本身所具有的的數據,而是包裹了x=1這個值,那麼也就是說不管以後在哪裏調用這個res函數,包裹的x=1這個值始終不變,x的值始終爲1。
9.5.1、閉包函數簡單例子理解
def outner():
x=1
def inner():
print(x)
return inner
res=outner() #此時的函數res可以看出是一個全局變量,在任何地方都可以被引用--用到了函數對象的概念。[函數outner()就相當於函數inner,那麼給inner函數賦值給res的話,函數res==函數inner]
res() #那麼在執行函數res()就相當於執行函數inner()
>>:1
def foo(): #res函數也可以被其他函數調用(函數res已經是全局變量了--用到了函數對象的概念)
print('from foo')
res()
foo()
>>:from foo
>>:1
9.5.2、閉包函數生產小例子
def sudada(url): #函數內傳參和在函數()傳參是一樣的
# url='https://www.baidu.com' #函數內傳參和在函數()傳參是一樣的
def foo():
import requests
response=requests.get(url)
if response.status_code == 200:
print(response.text)
return foo
baidu=sudada('https://www.baidu.com') #變量baidu其實等於函數foo
python=sudada('https://www.python.org') #變量python其實等於函數foo
baidu() #執行函數baidu(),就相當於執行函數foo()
python() #執行函數python(),就相當於執行函數foo()
五、裝飾器
裝飾器常用(套用)格式:
def outter(func):
def wrapper():
#代碼1
#代碼2
#代碼n...
return wrapper
1 開放封閉原則
軟件一旦上線之後就應該遵循開放封閉原則
具體是指對修改是封閉的,但對擴展是開放的
2、什麼是裝飾器
裝飾就是修飾,器指的就是工具
裝飾器本身: 可以是任意可調用的對象 --->>函數
被裝飾的對象:也可以是任意可調用的對象 --->>函數
3、裝飾器是用來爲被裝飾對象添加新功能的一種工具
必須遵循:
1、不能修改被裝飾對象的源代碼
2、不能修改被裝飾對象的調用方式
9.6.1、裝飾器例子1:
需求:查看一個index函數調用,花費了多長時間
-------------------------------------------方法1----------------------------------------
1、簡單實現需求:定義一個outer函數,在outer函數裏面調用index函數,在上一些邏輯判斷即可實現
import time
def index():
time.sleep(1)
print('welcome to index')
def outer(func):
start_time = time.time()
func()
stop_time = time.time()
print('run time is %s' %(stop_time - start_time))
outer(index)
得到的值如下:
welcome to index
run time is 1.000652551651001
-------------------------------------------方法2----------------------------------------
# 實現需求2:定義一個outer函數,在outer函數裏面再定義一個wrapper函數,通過wrapper函數來拿到index函數調用花費的時間,\
# 然後return wrapper函數,那麼調用outer函數時就會拿到一個返回值,我們可以把這個返回值定義爲 "index" 那麼使用 "index" 函數時 \
# 就相當於調用outer函數內的wrapper函數,實現的裝飾器的作用!
import time #導入time模塊
def index(): [被裝飾對象] #定義函數index(),在不改變函數index()的情況下,求執行"print('welcome to index')"這段代碼的開始時間與結束時間
time.sleep(1)
print('welcome to index')
def outter(func): [裝飾器] #func是outter函數的一個參數
def wrapper(): #wrapper就是用來統計時間差,這麼一個功能
start_time=time.time()
func() #在wrapper函數內調用func()時,先在wrapper函數內找(wrapper函數內沒有),然後在outter函數內找
stop_time=time.time()
print('run time is %s' %(stop_time - start_time))
return wrapper #返回函數wrapper的內存地址
#把outter(index)[內存地址]複製給index[這裏index指的是一個變量名,無意義]
index=outter(index) #函數outter(index)實際上就是函數wrapper的內存地址
#或者說調用wrapper函數,就相當於調用index(原始)函數
index() #執行函數index(),就相當於執行了函數wrapper()。{同時wrapper()==index()}
得到的值如下:
welcome to index
run time is 1.000652551651001
9.6.2、裝飾器例子2:原始函數index裏面需要返回值時(return)
import time
def index():
time.sleep(1)
print('welcome to index')
return 123 #這裏讓函數返回123
def outter(func):
def wrapper(): #wrapper函數的功能就是:1.測試index函數運行時間,2.拿到Index函數的返回值123
start_time=time.time()
res=func() #把返回值賦值給res
stop_time=time.time()
print('run time is %s' %(stop_time - start_time))
return res #在返回index函數的返回值
return wrapper
index=outter(index)
res=index()
print(res)
>>:welcome to index
>>:run time is 1.0006911754608154
>>:123
9.6.2、裝飾器語法糖:在被裝飾對象正上方單獨一行寫@裝飾器的名字
def timmer(func): [裝飾器名稱]
def wrapper(*args,**kwargs):....
return wrapper
@timmer [裝飾器語法糖]
def index():.... [被裝飾對象]
@timmer [裝飾器語法糖]
def home(name):.... [被裝飾對象]
9.6.3、無參裝飾器
import time
def timmer(func):
def wrapper(*args,**kwargs): #可以接受任意值[*接受所有溢出的位置參數,**接受所有的關鍵字參數]
start_time=time.time()
res=func(*args,**kwargs)
stop_time=time.time()
print('run time is %s' %(stop_time - start_time))
return res
return wrapper
@timmer # index=timmer(index)
def index(): #無參函數
time.sleep(1)
print('welcome to index')
return 1234
@timmer # home=timmer(home)
def home(name): #有參函數,參數name
time.sleep(2)
print('welcome %s to home page' %name)
index() #此處的函數index是被裝飾器timmer裝飾後的,而不是原始的index函數
>>:welcome to index
>>:run time is 1.000145673751831
home('sudada') #此處的函數home是被裝飾器timmer裝飾後的,而不是原始的home函數
>>:welcome egon to home page
>>:run time is 2.000617265701294
9.6.4、有參裝飾器
import time
current_user={'login':False}
def auth(engine):
def outter(func):
def wrapper(*args,**kwargs): # 這是一個閉包函數
if current_user['login']:
return func(*args,**kwargs) # 這調用的是被裝飾的函數[index()或者home(name)],並返回執行結果
user=input('username>>>: ').strip() #用戶登錄
pwd=input('password>>>: ').strip()
if engine == 'file': #判斷以哪種方式打開
if user == 'egon' and pwd == '123':
current_user['login']=True
return func(*args,**kwargs) # 這調用的是被裝飾的函數[index()或者home(name)],並返回執行結果
elif engine == 'mysql':
print('基於mysql數據的認證')
return func(*args, **kwargs)
elif engine == 'ldap':
print('基於ldap的認證方式')
return func(*args, **kwargs)
return wrapper # 返回閉包函數的執行結果
return outter # 返回閉包函數的執行結果
@auth(engine='mysql') # @outter # index=outter(index) #index=wrapper
def index():
time.sleep(1)
print('welcome to index')
return 1234
@auth(engine='ldap') # @outter # home=outter(home) #home=wrapper
def home(name):
time.sleep(2)
print('welcome %s to home page' %name)
index()
# username>>>: szq
# password>>>: 123
# 基於mysql數據的認證
home('egon')
# username>>>: egon
# password>>>: 123
# 基於ldap的認證方式