[TOC] 閉包函數 什麼是閉包函數 閉包函數把 閉包函數內的變數 + 閉包函數內部的函數, 這兩者包裹起來,然後通過返回值的形式返回出來。 定義在函數的內函數 該函數體代碼包含對該函數外層作用域中變數的引用 函數外層指的不是全局作用域 上述代碼中,f是一個全局的名字,但f拿到了inner的記憶體地址 ...
目錄
閉包函數
什麼是閉包函數
閉包函數把 閉包函數內的變數 + 閉包函數內部的函數, 這兩者包裹起來,然後通過返回值的形式返回出來。
- 定義在函數的內函數
- 該函數體代碼包含對該函數外層作用域中變數的引用
- 函數外層指的不是全局作用域
def outter():
x = 10
def inner():
print(x)
return inner
f = outter() # f=inner
f()
print(f)
# 列印結果:
10
<function outter.<locals>.inner at 0x00000201011A7840>
上述代碼中,f是一個全局的名字,但f拿到了inner的記憶體地址。將一個定義在內部的函數返回出來,在全局拿到f,這個f是全局變數,這樣就打破了函數的層級限制,能在任意位置使用內部的函數
閉包函數的應用
以參數的方式傳值
import requests
def get(url):
response = requests.get(url)
print(response.text)
get('https://www.baidu.com')
這裡寫了一個爬蟲函數,爬取百度的首頁。但這樣的問題就是每次想爬百度,或者其他網站都要傳一堆網址,比較麻煩,所以可以用閉包函數解決。
傳值另一方式: 包給函數
import requests
def spider(url):
def get():
response = requests.get(url)
print(response.text)
return get
baidu = spider('https://www.baidu.com')
baidu()
taobao = spider('https://www.taobao.com')
taobao()
這樣就很方便,以後調baidu,直接baidu()就行了
裝飾器
什麼是裝飾器
裝飾器就是 為需要裝飾的函數新增了一個額外的功能,裝飾器的本質就是一個 給函數增加功能的函數。
為什麼要裝飾器
裝飾器,增加功能需要註意以下幾點:
- 不改變原函數的原代碼
- 不改變原函數的調用方式
使用無參裝飾器
import time
def index():
'''被裝飾函數'''
time.sleep(1)
print('welcome to index')
index()
需要為上面的函數新增加一個功能,能夠統計函數運行的時間
在原代碼上修改
import time
def index():
start = time.time()
time.sleep(1)
print('welcome to index')
end = time.time()
print(f'run time is {end - start}')
index()
這樣就違反了不能修改原代碼這一原則
import time
def index():
time.sleep(1)
print('welcome to index')
start = time.time()
index()
end = time.time()
print(f'run time is {end - start}')
這樣寫就不是裝飾器,因為裝飾器是一個函數
利用函數傳參方式
import time
def index():
'''被裝飾函數'''
time.sleep(1)
print('welcome to index')
def time_count(func):
start = time.time()
func()
end = time.time()
print(f'run time is {end - start}')
time_count(index)
雖然實現了,但改變了函數調用方式
利用閉包
import time
def index():
'''被裝飾函數'''
time.sleep(1)
print('welcome to index')
def deco(func): # func = index 最初的index
def time_count():
start = time.time()
func()
end = time.time()
print(f'run time is {end - start}')
return time_count
# f = deco(index)
index = deco(index) # index = time_count
index()
這樣就簡單實現了一個裝飾器函數,調用index不是調用最初的index了,而是調用time_count函數,但用戶不知道,看起來就和原來使用一樣
裝飾器完善
上述的裝飾器,最後調用index()的時候,其實是在調用time_count(),因此如果原始的index()有返回值的時候,time_count()函數的返回值應該和index()的返回值相同,也就是說,我們需要同步原始的index()和time_count()方法的返回值。
import time
def index():
'''被裝飾函數'''
time.sleep(1)
print('welcome to index')
return 1234
def deco(func):
def time_count():
start = time.time()
res = func()
end = time.time()
print(f'run time is {end - start}')
return res
return time_count
# index = deco(index) # index = time_count
# index()
res = index()
print(res)
給原始index傳參
import time
def index(x):
'''被裝飾函數'''
time.sleep(1)
print('welcome to index')
return 1234
def deco(func):
def time_count(*args,**kwargs):
start = time.time()
res = func(*args,**kwargs)
end = time.time()
print(f'run time is {end - start}')
return res
return time_count
index = deco(index) # index = time_count
index(10)
使用裝飾器語法糖
import time
def deco(func):
def time_count(*args, **kwargs):
start = time.time()
res = func(*args, **kwargs)
end = time.time()
print(f'run time is {end - start}')
return res
return time_count
@deco # 這裡就相當於 index = deco(index)
def index(x):
'''被裝飾函數'''
time.sleep(1)
print('welcome to index')
return 1234
index(10)
裝飾器模板
def deco(func):
def wrapper(*args,**kwargs):
# 這裡加功能
res = func(*args,**kwargs)
return res
return wrapper
裝飾器小練習
# 寫一個登錄裝飾器,裝飾猜年齡,登錄了才能玩猜年齡
username_list = []
def guess(age):
print('welcome to guess age')
age_inp = input('請猜年齡').strip()
age_inp = int(age_inp)
if age_inp == age:
print('bingo')
elif age_inp < age:
print('猜小了')
else:
print('猜大了')
def login(func):
def wrapper(*args,**kwargs):
if username_list:
print('已登錄,請勿重覆登錄')
res = func(*args, **kwargs)
return res
username_inp = input('請輸入用戶名:').strip()
pwd_inp = input('請輸入密碼:').strip()
with open('user_info.txt', 'r', encoding='utf-8') as fr:
for user_info in fr:
user_info = user_info.strip()
username, pwd = user_info.split(':')
if username_inp == username and pwd_inp == pwd:
print('登錄成功')
username_list.append(username_inp)
res = func(*args, **kwargs)
return res
else:
print('登錄失敗')
res = func(*args,**kwargs)
return res
return wrapper
guess = login(guess)
guess(19)
有參裝飾器
import time
def outter(age):
def deco(func):
def wrapper(*args,**kwargs):
if age >= 18:
print('成年了')
else:
print('未成年')
start = time.time()
res = func(*args,**kwargs)
end = time.time()
print(f'run time is {end - start}')
return res
return wrapper
return deco
@outter(19) # 相當於 deco = outter(19) index = deco(index)
def index():
'''被裝飾函數'''
time.sleep(1)
print('welcome to index')
index()