Python-12
@(Python)
一、函数对象
- 函数是第一类对象,意思是函数可以被当做数据处理
- 函数对象:就是函数不带括号
- 函数对象,可以将定义在函数内的函数,通过
return
返回值,返回到全局中使用,从而打破函数的层级限制- Python中一切皆对象
func
和func()
的区别
func()
是函数的返回值func
函数名记录了值的内存地址(记录了值的内存地址,相当于连接函数名和值的线),函数名就是函数的内存地址print(func)
打印的是func函数名记录的值的内存地址print(func())
打印的是func函数的返回值
① 函数名可以被用来引用(赋值给一个变量)
# func是一个函数
y=x
f=func
print(f) # 就相当于print(func)
f() # f()就相当于func()调用函数
② 函数名当做参数传给一个函数
③ 函数名可以当做函数的返回值
④ 函数名可以当做容器类型的元素
可以把函数的内存地址(或理解为函数名的内存地址),当做元素
利用函数名为容器类型的元素,来调用函数
# 取款
def qk():
print('取款成功')
# 转账
def zz():
print('转账成功')
# 支付
def zf():
print('支付成功')
func_dict={
'1':qk,
'2':zz,
'3':zf,
}
while True:
msg='''
1. 取款
2. 转账
3. 支付
4. 退出
'''
print(msg)
func_num=input('输入数字>>')
if func_num == '4' : break
if func_num not in func_dict:
print('不在范围')
continue
func_dict[func_num]()
二、函数的嵌套
1. 函数的嵌套定义
- 函数的嵌套是在函数中再定义函数
- 在函数内中定义的函数,只能在这个函数内使用(一般情况下)
def func1():
def func2():
print('函数2')
- 通过函数嵌套,将一个大功能的小功能嵌套进去,不同的功能汇聚到一起,类似于封装成一个工具箱
- 例子:利用函数嵌套和函数对象当做容器元素,来写出计算圆面积和周长的功能
from math import pi # 计算圆的公式需要调用
def yuan(banjing,action):
def mianji():
return pi * (banjing ** 2)
def zhouc():
return pi * banjing * 2
if action == 'mianji':
return mianji() # 这是yun函数的返回值
elif action == 'zhouc':
return zhouc()
func1=input('半径>>')
func1=int(func1)
func2=input('计算类型>>')
print(yuan(func1,func2)) # 也可以使用默认形参固定一个常用的类型
2. 函数的嵌套调用
- 使用函数嵌套,在调用一个函数时,也调用了其他函数
- 如果一个功能可以被重复调用,就可以单独做成一个功能,使用其他函数再调用
三、名称空间与作用域
1. 名称空间
- 专门用来存名字的空间(变量名、函数名等的内存地址)
- 名称空间,是存放名字和值绑定关系的地方
① 内置名称空间
- 内置命名空间:Python解释器自带的名字
- 生命周期:在解释器启动时生效,在解释器关闭时失效
② 全局名称空间
- 全局名称空间:除了内置和局部空间外,其余都是全局名称空间
- 全局名称空间,是在文件执行时产生的(顶头写的代码使用的就是全局名称空间)
- 生命周期:在文件执行时生效,在文件执行完毕后失效
③ 局部名称空间
- 存放函数调用期间函数体产生的名字,即函数内定义的名字
- 生命周期:执行文件时,只有被调用了才会临时生效,在函数执行完毕后失效,自动释放
内置、全局、局部名称空间的加载顺序
① 内置名称空间--->② 全局名称空间--->③ 局部名称空间
内置、全局、局部名称空间的查找顺序
① 局部名称空间--->② 全局名称空间--->③ 内置名称空间
- 基于当前位置,然后按顺序找
2. 作用域
- 作用域就是名称空间的作用的范围,是对名称空间的再分类
① 全局作用域
- 全局作用域:就是全局作用范围,包括:内置名称空间和全局名称空间
- 全局有效:内置命名空间和全局命名空间
- 全局存活:从程序开始存活,一直到程序的结束
② 局部作用域
- 局部作用域:就是局部作用范围,包括:局部命名空间
- 局部有效,临时存活
- 作用域关系是在函数定义阶段就固定好了,但凡要调用函数就需要去函数的定义阶段找作用域关系
x=10
def func1():
print(x)
x=10000000000000000000000
def func2():
x=11111111111
func1()
func2() # 以调用为分隔符,往前找
x=10
def func1():
x=777777777777777777 # 先找局部空间,再找全局空间,全局空间有多个找上面最近的
print(x)
x=10000000000000000000000
def func2():
x=11111111111
func1()
func2() # 以调用为分隔符,往前找
③ 作用域的应用:
- 打破层级限制,利用
return
将函数名转到全局,再调用
def f1():
def inner():
print('from inner')
return inner
f1()() # f1()得到的是return的值,相当于inner,f1()() == inner()
# 或者
f=f1()
f() # 相当于f1()()
def f1():
x=1
def inner():
print('from inner',x)
return inner
f=f1() # 相当于f=inter
def bar():
x=11111111111111
f() # 相当于inter()
bar()
- 说明:回到定义阶段,按照先局部,后全局的顺序找,如果局部没有才找全局,如果有多个全局,就以调用函数为分隔线,往上找最近的
- 在函数体内,改全局的东西,需要使用
global x
,比如global x
将x
拿到全局用,同代码段往下找最后一个- 但是尽量不要改全局,尽量做成独立的功能,对其他无影响
x=1
def foo():
global x
x=111
foo()
print(x)
nonlocal
会往本函数体外层找,往上找最近的,但是还是在大的函数内,找到就改,找不到就报错
x=1
def f1():
def f2():
x=2222222 # 找到的内容
def f3():
nonlocal x
x=111111111111 # 要改成什么
f3()
print(x) # 打印这一层的,看nonlocal是后生效
f2()
f1()
- 在局部如果想要修改全局的可变类型,不需要借助任何声明,可以直接修改,比如可以改字典,列表等
- 在局部如果想要修改全局的不可变类型,需要借助
global
声明,声明为全局的变量就可以直接修改