回顧:
- 函數對象:可以將定義在函數內的函數返回到全局使用,從而打破函數的層級限制。
- 名稱空間與作用域:作用域關系在函數定義階段時就已經固定死了,與調用位置無關,即在任意位置調用函數都需要跑到定義函數時找到作用域關系。
def f1():
x = 1
def inner():
print(x)
return inner
func = f1()
x = 2
def f2():
x = 3
func()
f2()
1
一、什么是閉包?
閉包:閉是封閉(函數內部函數),包是包含(該內部函數對外部作用域而非全局作用域的變量的引用)。閉包指的是:函數內部函數對外部作用域而非全局作用域的引用。
提示:之前我們都是通過參數將外部的值傳給函數,閉包提供了另外一種思路,包起來嘍,包起呦,包起來哇。
def outter():
x = 1
def inner():
print(x)
return inner
f = outter()
def f2():
x = 2
f()
f2()
1
1.1 兩種為函數傳參的方式
為函數傳參的方式一:使用參數的形式
def func(x):
print(x)
func(1)
func(1)
func(1)
1
1
1
為函數傳參的方式二:包給函數
def outter(x):
x = 1
def inner():
print(x)
return inner
f = outter(1)
f()
f()
f()
# 查看閉包的元素
print(F"f.__closure__[0].cell_contents: {f.__closure__[0].cell_contents}")
1
1
1
f.__closure__[0].cell_contents: 1
二、閉包函數的應用
閉包的意義:返回的函數對象,不僅僅是一個函數對象,在該函數外還包裹了一層作用域,這使得,該函數無論在何處調用,優先使用自己外層包裹的作用域。
應用領域:延遲計算(原來我們是傳參,現在我們是包起來)、爬蟲領域。
import requests
def get(url):
response = requests.get(url)
print(f"done: {url}")
get('https://www.baidu.com')
get('https://www.baidu.com')
get('https://www.baidu.com')
get('https://www.cnblogs.com/linhaifeng')
get('https://www.cnblogs.com/linhaifeng')
get('https://www.cnblogs.com/linhaifeng')
done: https://www.baidu.com
done: https://www.baidu.com
done: https://www.baidu.com
done: https://www.cnblogs.com/linhaifeng
done: https://www.cnblogs.com/linhaifeng
done: https://www.cnblogs.com/linhaifeng
上面的方式是極其復雜的,我們如果使用默認參數也只能解決一個網址,因此我們可以考慮使用閉包的方式。
import requests
def outter(url):
def get():
response = requests.get(url)
print(f"done: {url}")
return get
baidu=outter('https://www.baidu.com')
python = outter('https://www.python.org')
baidu()
baidu()
python()
python()
done: https://www.baidu.com
done: https://www.baidu.com
done: https://www.python.org
done: https://www.python.org