函数对象指的是函数可以被当作数据来处理,具体可以分为四个方面的使用。
# 1、函数可以被引用
def add(x, y):
return x + y
func = add
print(func(1, 2))
# 2、函数可以作为容器类型元素
dic = {'add': add, 'max': max}
print(dic['add'](1, 2))
print(dic['max'](1, 2))
# 3、函数可以作为参数传入另外一个函数
def foo(x, y, z):
return z(x, y)
print(foo(1, 2, add))
# 4、函数的返回值可以是一个函数
def bar():
return add
func = bar()
print(func(1, 2))
# 结果
3
3
2
3
3
所谓的闭指的是这个函数是一个函数内的函数。
所谓的包指的是闭函数引用了一个变量,而这个变量却来自于外层函数,就称之为包。
基于函数对象的概念,可以将函数返回到任意位置去调用,但是作用域的关系是在定义完函数的时候就已经被确定了的,与函数的调用位置无关。
x = 1
def f1():
def f2():
print(x)
return f2()
def f3():
x = 3
f2 = f1() # 调用f1()返回函数f2
f2 # 需要按照函数定义时的作用关系去执行,与调用位置无关
f3()
# 结果
1
也就是说函数被当作数据处理时,始终以自带的作用域为准。如果内嵌函数包含对外部函数作用域(而非全局作用域)中变量的引用,那么该内嵌函数就是闭包函数,简称闭包(Closures)
x = 1
def outer():
x = 2
def inner():
print(x)
return inner()
func = outer()
func
# 结果
2
目前为止,我们得到了两种为函数体传值的方式,一种是直接将值以参数的形式传入,另外一种就是将值包给函数
requests模块是用来模拟浏览器向网站发送请求并将页面内容下载到本地,需要事先安装:python3 -m pip install requests
对比两种方式,方式一在下载同一个页面事需要重复传入URL,而方式二只需要传一次值,就会得到一个包含指定URL的闭包函数,以后调用该函数无需再传URL
import requests
import time
# 方式一
def get(url):
return print(len(requests.get(url).text))
# 方式二
def page(url):
def get():
return print(len(requests.get(url).text))
return get
# 方式一运行
get("https://dudewu.top/website")
time.sleep(2)
get("https://dudewu.top/website")
time.sleep(2)
get("https://dudewu.top/website")
# 方式二运行
aaa = page("https://dudewu.top")
aaa()
time.sleep(2)
aaa()
time.sleep(2)
aaa()
闭包函数的这种特性有时候又称为惰性计算,使用将值包给函数的方式,在接下来的装饰器中也将大有用处