-
引子
-
函数对象
-
函数嵌套
-
名称空间与作用域
-
闭包函数
-
函数对象
在python中,函数是第一类对象,即函数可以当做数据传递,函数又称第一等公民
本质:函数可以当变量用
-
1.可以赋值
def func(): # func = 函数的内存地址
print('from func')
f = func # func 可以赋值给其它变量
print(f)
f()
-
2.可以当做参数传给另外一个函数
def func():
print('from func')
def foo(x):
print(x)
x() # 可以加()触发内部代码的运行
foo(func)
-
3.可以当做函数的返回值
def func():
print('from func')
def foo(x): # 把func丢进去
return x # 紧接着又扔出来func
res = foo(func)
print(res)
-
4.可以当做容器类型的元素
def func():
print('from func')
l = [func,] # 列表调用
print(l)
l[0]()
# 容器类型的元素的应用
# 购物车程序
def withdraw():
print("提款")
def tranfer():
print("转账")
def check_balance():
print("查询余额")
def save():
print("存款")
func_dic = {
"1":["提款",withdraw],
"2":["转账",tranfer],
"3":["查询余额",chenk_balance],
"4":["存款",save]
}
while True:
print("0 退出")
for k,v in func_dic.items():
print(k,v[0])
choice = input("请输入您要操作的编号>>>:").strip()
if choice == '0':
break
if choice in func_dic:
func_dic[choice][1]()
else:
print("输入错误")
-
函数嵌套
-
函数的嵌套调用
def max2(x,y): # 比较两个值的大小
if x > y:
return x
else:
return y
def max4(a,b,c,d): # 求四个值的最大值
res1 = max2(a,b)
res2 = max2(res1,c)
res3 = max2(res2,d)
return res3
print(max4(11,99,33,12))
# 把一个大功能拆解成几个小功能,然后再把每个小功能分别去实现,最后在拼接回来
-
函数的嵌套定义
def f1():
x = 10 # 变量丢到函数里面是一个封闭的效果
def f2():
print('from f2')
print(x) #1 这两行代码是站在内部去看的可以看见
print(f2) #2
f1()
print(x) #1 这两行代码是站在外面去看的是看不见的
print(f2) #2
# 函数层级带来的变量访问的限制,到底是因为什么?定义在某一个位置的东西到底在哪才能看得见?
-
名称空间与作用域
-
namespaces名称空间:存放名字的地方
内置名称空间:存放内置的名字
生命周期:python解释器启动则产生,关闭则销毁
全局名称空间:存放的是顶级的名字
生命周期:运行python文件时则产生,python文件运行完毕则销毁、
局部名称空间:存放的是函数内的名字
生命周期:调用函数则产生,函数调用完毕则销毁
# 内置名称空间:
>>> input
<built-in function input> # built-in 内置
# 全局名称空间:
x = 10 # 变量名X
y = 20 # 变量名y
f 1 > 0:
z = 30
with open('a.txt', mode='wt') as f:
a = 333
while True:
c = 444
# 以上都是属于顶级的
# 局部名称空间:
x = 10 # 全局名称空间
def foo(m): # 全局名称空间
m = 111 # 调用函数时,才会执行函数代码,名字m和n都存放于该函数的局部名称空间中
n = 222 # 函数内
foo(111) # 调用产生函数名称空间
名称空间的加载顺序是:内置名称空间--->全局名称空间--->局部名称空间
而查找一个名字,必须从三个名称空间之一找到
查找顺序为:局部名称空间--->全局名称空间--->内置名称空间
核心:名字的访问优先级
基于当前所在的位置向外查找
# 案例1
len = 10 # 全局名称空间
def func(): # 函数
len = 20
# print(len) # 站在局部查找,找到的是20
func() # 调用产生局部名称空间
print(len) # 站在全局找,全局有找全局,全局没有找内置
# 案例2
def f1():
x = 555
def f2():
x = 666
print(x)
f2()
x = 444
f1()
-
作用域(******)
名称空间与作用域的关系是在函数定义阶段(扫描语法时)就确立的,
与什么时候调用以及调用位置无关
x = 111
def f1():
print(x)
def f2():
x = 222
f1()
f2()
# 案例2
x = 111
def f1():
print(x)
x = 222
f1()
-
作用域
全局作用域:内置名称空间 + 全局名称空间
特点:全局存活(除非被删除,否则在整个文件执行过程中存活)
全局有效(在任意位置都可以使用)
局部作用域:局部名称空间
特点:临时存活(即在函数调用时临时生成,函数调用结束后就释放)
局部有效(只能在函数内使用)
-
global关键字
在函数内,无论嵌套多少层,都可以查看到全局作用域的名字,若要在函数内修改全局名称空间中名字的值,当值为不可变类型时,则需要用到global关键字
# 案例1:
l = []
def func():
l.append(1111)
# l = [11,22,33]
func() # 调func执行append
print(l)
# 当全局变量是可变类型的时候,局部是可以直接改的
# 案例2:
x = 111 # 全局变量不可变类型
def func():
global x # 声明X是属于全局的,是可以改变的
x = 222 # 在局部产生新的名字不影响全局
func()
print(x)
# 要想在局部修改一个全局的不可变类型,可以用global修改
-
nonlocal关键字
对于嵌套多层的函数,使用nonlocal关键字可以将名字声明为来自外层嵌套函数定义的作用域(非全局)
x = 111
def f1():
# x = 222
def f2():
# global x # 声明变量名是来自全局的
nonlocal x # 声明变量名是来自于外层函数的,不是全局
x = 333 # 要想在这个位置用global把x=222改掉不可能
f2()
print(x)
f1()
-
闭包函数
闭:指的该函数是定义在函数内的函数
包:指的就是该函数引用了一个外层函数作用域的名字(e作用域的名字)
def outter():
x = 111 # 为wrapper函数的函数体代码传参
def wrapper():
print(x)
# 以后无论wrapper在哪调,它访问的x以定义阶段为准。
def outter(): # outter最外层函数
x = 111
def wrapper(): # 把wrapper闭到了outter里面了,wrapper就只能在里面用
print(x)
return wrapper # 千万别加括号,要想把wrapper从里面扔出来用就需要用return
f = outter() # 把一个内部函数扔到全局,这个内部函数就打破了层级限制,可以在任意位置调用
print(f)
def foo():
x = 222
f() # 此时调f就相当于调wrapper
foo()
-
为函数代码体传参的方案
方案一:直接用参数传
def wrapper(x):
print(x)
wrapper(111)
wrapper(222)
wrapper(333)
方案二:闭包函数
def outter(x): # 为了给wrapper函数传参只能把它扔进去,wrapper本来是顶级的
def wrapper():
print(x)
return wrapper # 参数传完就把wrapper用return扔出去
f1 = outter(111) # 再想拿到wrapper,调outter拿到返回值,f1相当于当初的wrapper
f1()
f2 = outter(222)
f2()