python基础-函数对象和闭包
一 函数对象
函数对象指的是函数可以被当做’数据’来处理,具体可以分为四个方面的使用,我们如下
1.1 函数可以被引用
>>> def add(x,y): ... return x+y ... >>> func=add >>> func(1,2) 3
1.2 函数可以作为容器类型的元素
>>> dic={'add':add,'max':max} >>> dic {'add': <function add at 0x100661e18>, 'max': <built-in function max>} >>> dic['add'](1,2) 3
1.3 函数可以作为参数传入另外一个函数
>>> def foo(x,y,func): ... return func(x,y) ... >>> foo(1,2,add) 3
1.4 函数的返回值可以是一个函数
def bar(): return add func=bar() func(1,2) 3
# 精髓:可以把函数当成变量去用 # func=内存地址 def func(): print('from func') # 1、可以赋值 # f=func # print(f,func) # f() # 2、可以当做函数当做参数传给另外一个函数 # def foo(x): # x = func的内存地址 # # print(x) # x() # # foo(func) # foo(func的内存地址) # 3、可以当做函数当做另外一个函数的返回值 # def foo(x): # x=func的内存地址 # return x # return func的内存地址 # # res=foo(func) # foo(func的内存地址) # print(res) # res=func的内存地址 # # res() # 4、可以当做容器类型的一个元素 # l=[func,] # # print(l) # l[0]() # dic={'k1':func} # print(dic) # dic['k1']() # 函数对象应用示范: # def login(): # print('登录功能') # # # def transfer(): # print('转账功能') # # # def check_banlance(): # print('查询余额') # # def withdraw(): # print('提现') # # # def register(): # print('注册') # # func_dic={ # '1':login, # '2':transfer, # '3':check_banlance, # '4':withdraw, # '5':register # } # # # func_dic['1']() # # # while True: # print(""" # 0 退出 # 1 登录 # 2 转账 # 3 查询余额 # 4 提现 # 5 注册 # """) # choice = input('请输入命令编号:').strip() # if not choice.isdigit(): # print('必须输入编号,傻叉') # continue # # if choice == '0': # break # # # if choice in func_dic: # func_dic[choice]() # else: # print('输入的指令不存在') # # # if choice == '1': # # login() # # elif choice == '2': # # transfer() # # elif choice == '3': # # check_banlance() # # elif choice == '4': # # withdraw() # # else: # # print('输入的指令不存在') # 修正 def login(): print('登录功能') def transfer(): print('转账功能') def check_banlance(): print('查询余额') def withdraw(): print('提现') def register(): print('注册') func_dic = { '0': ['退出', None], '1': ['登录', login], '2': ['转账', transfer], '3': ['查询余额', check_banlance], '4': ['提现', withdraw], '5': ['注册', register] } # func_dic['1']() while True: for k in func_dic: print(k, func_dic[k][0]) choice = input('请输入命令编号:').strip() if not choice.isdigit(): print('必须输入编号,傻叉') continue if choice == '0': break # choice='1' if choice in func_dic: func_dic[choice][1]() else: print('输入的指令不存在')
# 函数嵌套 # 1、函数的嵌套调用:在调用一个函数的过程中又调用其他函数 # def max2(x,y): # if x > y: # return x # else: # return y # # # def max4(a,b,c,d): # # 第一步:比较a,b得到res1 # res1=max2(a,b) # # 第二步:比较res1,c得到res2 # res2=max2(res1,c) # # 第三步:比较res2,d得到res3 # res3=max2(res2,d) # return res3 # # res=max4(1,2,3,4) # print(res) # 2、函数的嵌套定义:在函数内定义其他函数 # def f1(): # def f2(): # pass # 圆形 # 求圆形的求周长:2*pi*radius def circle(radius,action=0): from math import pi def perimiter(radius): return 2*pi*radius # 求圆形的求面积:pi*(radius**2) def area(radius): return pi*(radius**2) if action == 0: return 2*pi*radius elif action == 1: return area(radius) circle(33,action=0)
二 闭包函数
2.1 闭与包
基于函数对象的概念,可以将函数返回到任意位置去调用,但作用域的关系是在定义完函数时就已经被确定了的,与函数的调用位置无关。
# 一:大前提: # 闭包函数=名称空间与作用域+函数嵌套+函数对象 # 核心点:名字的查找关系是以函数定义阶段为准 # 二:什么是闭包函数 # "闭"函数指的该函数是内嵌函数 # "包"函数指的该函数包含对外层函数作用域名字的引用(不是对全局作用域)
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
可以通过函数的closure属性,查看到闭包函数所包裹的外部变量
>>> func.__closure__ (<cell at 0x10212af78: int object at 0x10028cca0>,) >>> func.__closure__[0].cell_contents 2
“闭”代表函数是内部的,“包”代表函数外’包裹’着对外层作用域的引用。因而无论在何处调用闭包函数,使用的仍然是包裹在其外层的变量。
2.2 闭包的用途
目前为止,我们得到了两种为函数体传值的方式,一种是直接将值以参数的形式传入,另外一种就是将值包给函数
import requests #方式一: def get(url): return requests.get(url).text #方式二: def page(url): def get(): return requests.get(url).text return get
提示:requests模块是用来模拟浏览器向网站发送请求并将页面内容下载到本地,需要事先安装:pip3 install requests
对比两种方式,方式一在下载同一页面时需要重复传入url,而方式二只需要传一次值,就会得到一个包含指定url的闭包函数,以后调用该闭包函数无需再传url
# 方式一下载同一页面 get('https://www.python.org') get('https://www.python.org') get('https://www.python.org') …… # 方式二下载同一页面 python=page('https://www.python.org') python() python() python() ……
闭包函数的这种特性有时又称为惰性计算。使用将值包给函数的方式,在接下来的装饰器中也将大有用处
# 闭包函数:名称空间与作用域的应用+函数嵌套 # def f1(): # x = 33333333333333333333 # def f2(): # print(x) # f2() # # # x=11111 # def bar(): # x=444444 # f1() # # def foo(): # x=2222 # bar() # # foo() # 闭包函数:函数对象 # def f1(): # x = 33333333333333333333 # def f2(): # print('函数f2:',x) # return f2 # # f=f1() # # print(f) # # # x=4444 # # f() # def foo(): # x=5555 # f() # # foo() # 三:为何要有闭包函数=》闭包函数的应用 # 两种为函数体传参的方式 # 方式一:直接把函数体需要的参数定义成形参 # def f2(x): # print(x) # # f2(1) # f2(2) # f2(3) # 方式二: # def f1(x): # x=3 # x=3 # def f2(): # print(x) # return f2 # # x=f1(3) # print(x) # # x() import requests # 传参的方案一: # def get(url): # response=requests.get(url) # print(len(response.text)) # # get('https://www.baidu.com') # get('https://www.cnblogs.com/linhaifeng') # get('https://zhuanlan.zhihu.com/p/109056932') # 传参的方案二: def outter(url): # url='https://www.baidu.com' def get(): response=requests.get(url) print(len(response.text)) return get baidu=outter('https://www.baidu.com') baidu() cnblogs=outter('https://www.cnblogs.com/linhaifeng') cnblogs() zhihu=outter('https://zhuanlan.zhihu.com/p/109056932') zhihu()
每天学习新的知识,会让自己更加充实