1 函数对象
精髓:可以把函数当成变量去用
# func=内存地址 定义一个函数, 实际就是给函数开辟一个内存空间
def func():
print(func)
func()
>>
<function func at 0x00000285702A6310>
1.1 可以赋值
def func():
print('from func')
f=func # 把func的内存地址赋值给f, 注意, 这里不能用f=func(), 这就变成了把函数的返回值赋值给f
# func()函数定义在全局, 因此, 在函数内部可以拿到
print(f,func)
f()
>>
<function func at 0x000001296AAA61F0> <function func at 0x000001296AAA61F0>
from func
函数A的内存地址复制给B
那么B()就是直接运行函数A了
1.2 可以把函数当做参数传给另外一个函数
def func():
print('from func')
def foo(x): # x = func的内存地址
print(x)
foo(func)
>>
<function func at 0x00000243CB3E61F0>
***********************************************************************************************************
def func():
print('from func')
def foo(x): # x = func的内存地址
x() # x就是func的内存地址, 因此可以直接x()运行, 就相当于运行func()
foo(func)
>> from func
1.3 可以把函数当做另外一个函数的返回值
def func():
print('from func')
def foo(x): # x=func的内存地址
return x # return func的内存地址
res=foo(func)
# foo(func的内存地址)
print(res) # res=func的内存地址
res()
>>
<function func at 0x0000017D038961F0>
from func
1.4 可以当做容器类型的一个元素
def func():
print('from func')
l=[func,]
print(l)
>> [<function func at 0x000001B483FA61F0>]
l[0]()
>> from func
def func():
print('from func')
dict1 = {'k1':func}
print(dict1['k1'])
dict1['k1']()
print(dict1)
>>
<function func at 0x00000214317861F0>
from func
{'k1': <function func at 0x00000263299261F0>}
1.5 函数对象案例
模拟ATM功能
def login():
print('登录功能')
def transfer():
print('转账功能')
def check_balance():
print('查询余额')
def withdraw():
print('提现')
def register():
print('注册')
func_dic={
'1':login,
'2':transfer,
'3':check_balance,
'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_balance()
# elif choice == '4':
# withdraw()
# else:
# print('输入的指令不存在')
# 修正
def login():
print('登录功能')
def transfer():
print('转账功能')
def check_balance():
print('查询余额')
def withdraw():
print('提现')
def register():
print('注册')
func_dic = {
'0': ['退出', None],
'1': ['登录', login],
'2': ['转账', transfer],
'3': ['查询余额', check_balance],
'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('输入的指令不存在')
最终整理
def login():
print('登录功能: ')
def balance():
print('查询余额: ')
def withdraw():
print('取款: ')
def transfer():
print('转账: ')
# 使用字典, 存放选项和函数对象, 后期添加或者减少功能, 只需要修改字典内的元素, 并且修改函数功能即可. 对于while循环内的代码, 是不用更改的
function_dict = {
'0':['退出',None], # 由于程序运行期间, 列表的元素是不会改的, 因此, 可以用元组代替.
'1':['登录功能',login],
'2':['查询余额',balance],
'3':['取款',withdraw],
'4':['转账',transfer],
}
while True:
for k in function_dict:
print(k,'>>',function_dict[k][0])
choice = input('请输入指令: ').strip()
if not choice.isdigit():
print('请输入对应的数字指令: ')
continue
if choice == '0':
print('退出程序!!!')
break
if choice in function_dict:
function_dict[choice][1]()
else:
print('请输入正确的指令!!!')
2 函数嵌套
2.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.2 函数的嵌套定义
在函数内定义其他函数, 外层函数可以访问内层函数, 想让f2被所有人用到, 就放到全局, 如果想被某一个函数调用, 就写到这个函数里面嵌套
把f1当成容器看, 只有f1能用自己容器内的函数
def f1():
def f2():
pass
求圆形的周长和面积
def circle(radius,action=0): # 通过action=0, 默认形参, 配合if判断, 可以实现根据传参来执行函数
from math import pi
# 求圆形的周长: 2*pi*radius
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)
result = circle(1,action=0)
print(result)
3 闭包函数
3.1 介绍
闭包函数=名称空间与作用域+函数嵌套+函数对象
核心点:名字的查找关系是以函数定义阶段为准
3.2 什么是闭包函数
"闭"函数指的该函数是内嵌函数
"包"函数指的该函数包含对外层函数作用域名字的引用(不是对全局作用域)
闭包函数:名称空间与作用域的应用+函数嵌套
def f1():
x = 33333333333333333333
def f2(): # 把f2定义在f1内, 即为闭函数, 只有该f2函数的外层函数f1能访问到
print(x) # f2中的x引用的是其外层f1函数作用域的x, 因此, 称为包函数
f2()
x=11111
def bar():
x=444444
f1()
def foo():
x=2222
bar()
foo()
>> 33333333333333333333
3.2.1 闭包函数应用1
名称空间与作用域的应用+函数嵌套
def f1():
x = 33333333333333333333
def f2():
print(x)
f2()
x=11111
def bar():
x=444444
f1()
def foo():
x=2222
bar()
foo()
>> 33333333333333333333
3.2.2 闭包函数应用2
基于函数对象, 实现在全局作用域拿到内层函数的内存地址
无论在哪里调用该内层函数, 其名称的查找关系都是在定义阶段确定的, 也就是其外层函数的作用域
def f1():
x = 33333333333333333333
def f2():
print('函数f2:',x) # 33333333333333333333
return f2 # 返回f2函数的内存地址, 该内存地址, 可以被f1拿到
f=f1() # f1()函数的返回值是f2函数的内存地址, 赋值给f, 那么f就等于f2的内存地址, 此时f2作为内层函数, 其内存地址可以在全局通过f访问到
print(f)
# x=4444
# f()
def foo():
x=5555
f()
foo()
>>
<function f1.<locals>.f2 at 0x000001AA966B5DC0>
函数f2: 33333333333333333333 # 函数f2在f1内是没有调用的, 只有当执行了foo函数内部代码f()时, 才是调用f2函数. 因此, f2内部的print是后执行的
4 函数传参的两种方式
为何要有闭包函数=》闭包函数的应用
两种为函数体传参的方式
4.1 利用实参给形参传参
直接把函数体需要的参数定义成形参
def f2(x):
print(x)
f2(1)
f2(2)
f2(3)
4.2 利用闭包函数
利用名称空间, 使用闭包函数传参
def f1(x): # x=3
# x=3
def f2(): # 实际需要用的函数是f2, 但是因为f2写在了f1内, 因此, 在全局是无法调用的, 需要利用函数对象, 把f2的内存地址, 传给全局的变量x
print(x)
return f2
x=f1(3) # 给f1传3, 就相当于在f1内部, 定义x=3, 然后被f2调用.
print(x)
x()
>>
<function f1.<locals>.f2 at 0x000001E7DAFF5DC0> # 先调用f1, 把返回的
# f2的内存地址, 赋值给全局变量x, 之后print(x), 拿到f2的内存地址
3 # 最后调用x(), 才是执行f2函数的代码, print(x), f2的x在定义阶段已经确定, 需要使用
# 外层f1内的x的值
4.3 闭包函数传参案例
import requests
传参的方案一:通过实参给形参传参
def get(url):
response=requests.get(url)
print(len(response.text))
get('https://www.baidu.com')
get('https://www.jianshu.com')
get('https://www.zhihu.com')
>>
2443
584
166
传参的方案二:利用闭包传参
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() # 之后再运行内层函数
jianshu=outter('https://www.jianshu.com/')
jianshu()
zhihu=outter('https://www.zhihu.com/')
zhihu()
网友评论