函数的名称空间和作用域
一、函数是第一类对象
1.函数:
-定义:
函数的名字就是函数的对象,函数名指向的函数的内存地址。
-有什么用?
-可以被引用
-可以被当作参数传入
-可以当作函数的返回值
-可以当作参数传入容器中
函数对象的应用:
可以优雅的的取代if的分支
def index():
'''
无参函数
'''
print('from index')
print(index) ##打印的是变量名的内存地址
>>>>>>
<function index at 0x0000015038D81EA0>
def index(l1):
'''
求列表的长度
'''
print(len(l1))
l1 = [1,2,4,'afew']
index(l1) ######调用函数 打印上面的print 的值 4
print(index(l1))####有index()都是要调用函数,打印上面的print print(index())打印返 回值,没有return 则返回none
>>>>>>>
4
4
None
1.函数名是可以被引用的
name = 'tank'
dsb = name
与上面的是类似的用法
f=def index():
'''
可以被引用
'''
print('from the index')
a = index
a()
>>>>>>
from the index
2.函数名可以当作参数传递
def foo(x,y,func):
'''
函数的名可以当作参数传递
'''
print(x,y)
func()
def bar():
print('from the bar')
foo(1,2,bar)
>>>>>>
1 2
from the bar
3.函数名可以当作返回值使用,
传参的时候没有特殊要求,一定不要加括号,加括号当场执行
def index():
'''
函数名可以当作返回值用
'''
print('from the index')
def func(a):
return(a)
b = func(index) ##### index === return 中 的a 下main就是 index()
b()
>>>>>>>
from the index
4、函数名可以被当做容器类型的元素
def func():
'''
函数名可以作为容器类型的元素
'''
print('from ')
l1 = [1,2,func,func()]#####正常的python解释器的走向 从上到下 从左到右 定格写的 (1,2,func()) 也可以调用func()的函数
f = l1[2]
print(f)
>>>>>>>
from
<function func at 0x0000016D90FC1EA0> ####func的内存地址
购物车的一个程序
def register():
print('register')
def login():
print('login')
def shopping():
print('shopping')
def pay():
print('pay')
func_dic = {
'1' : register,
'2' : login,
'3' : shopping,
'4' : pay
}
def main():
while True:
print('''
1、注册
2、登录
3、购物
4、付款
''')
choice = input('请输入对应的编号: ').strip()
if choice == '5':
break
elif choice not in func_dic:
continue
else:
func_dic[choice]()
main()
二、函数的嵌套
-函数的嵌套的定义:
-让内层函数封闭起来,不让外部直接调用。
-作用
-将功能并且小的功能,在函数内部调用,解决代码结构清晰问题。
def index():
''''
函数的嵌套
'''
print('from the world')
def func():
index()
print('from the world')
func()
>>>>>>
from the world
from the world
举例 2
def index(x, y):
'''
函数的嵌套
'''
if x > y:
return x
else:
return y
print(index(index(index(1,2),3),6))
print(index(1,4))
>>>>>>>
6
4
举例3
def index(x, y):
'''
函数的嵌套
'''
if x > y:
return x
else:
return y
def index_2(x,y,z,a):
result = index(x,y)
result = index(result, z)
result = index(result,a)
return result
print(index_2(1,2000,3,1000))
>>>>>>
2000
举例4
def index():
'''
函数的嵌套
'''
def home():
print('well')
home()
index()
>>>>>>
well
三、名称空间
什么是名称空间?
存放名字的空间 名称空间是一个在内存种的空间
如果你想访问一个变量值,必须先访问对应的名称空间,拿到名字和对应的内存地址的绑定关系
名称空间的分类:
1、内置名称空间:
python提前给你的定义完的名字,就是存在内置名称空间
print(input)
>>>>>>
<built-in function input>
2、全局名称空间
存放于文件级别的名字,就是全局名称空间
if while for 内部定义的名字执行之后都存放于全局名称空间
x = 1
print(x)
3、局部名称空间
函数内部定义的所有名字都是存放与当前函数的内置名称空间
生命周期:
1、内置名称空间
在python解释器启动的时候生效,关闭解释器的时候销毁
2、全局名称空间
当你启动当前这个py文件的时候生效,当前页面代码执行结束之后销毁,关闭python解释器时,彻底 销毁。
x = 1 ####这个变量就是存放于全局名称空间
def index():
'''
取x的值
'''
print(x)
index()
>>>>>>>>>>
1
Process finished with exit code 1 ####这个代表的是代码执行结束
3、局部名称空间
当你调用当前函数时生效,临时存活,函数调用结束后销毁。
def index():
x = 1 ###变量存放于局部的名称空间。
print(x)
index()
>>>>>>
1
下图是名称空间的图片
![img](file:///C:\Users\86187\Documents\Tencent Files\1341212001\Image\Group\3K0L@[`%FVSWG}UW]6YQJLV.jpg)
四、名称空间的查找顺序
def index():#####index是全局变量名称空间
'''
print的值
'''
x = 1 ######x 是局部名称变量空间
return x
print(index)#####没有执行函数,但是内存地址在定义函数的时候已经确定了,所以可以打印的出来
def foo():
print(index) ######执行函数 打印的是index的内存地址
foo()
>>>>>>>>
<function index at 0x0000029F5B0A1EA0>
<function index at 0x0000029F5B0A1EA0>
######名称空间的查找顺序:######
-加载顺序:内置--->全局---->局部
-查找顺序:局部--->全局---->内置
# 函数内部使用的名字,在义阶段已经规定死了,与你的调用位置无关
如下图的是print(x)是函数内部使用的名字
x = 1
def index():
'''
查看局部变量
'''
print(x)
def wrapper():###这个是个局部的变量 不能赋给到上面的一层
x = 2
index()
wrapper()
>>>>>
1
下面的例子
x = 1
def index():
'''
查看局部变量
'''
x = 3 #####局部从新有了名称空间,先用局部的 ,局部没有的话,才会去找全局的,wrapper属于是内层的嵌套,更低一级,也是不能操作的
print(x)
def wrapper():
x = 2
index()
wrapper()
>>>>>
3
x = 1
def inner():
x = 2
def wrapper():
print(x)####上面一层的x =2是最后赋值的
wrapper()
x = 111
inner()
>>>>>>>
2
下面的一个例子
x = 1
def inner():
# x = 2
def wrapper():
print(x)
wrapper()
x = 111
inner()
>>>>>>>
111
全局变量名称空间的一个例子
x = 1
def index():
x = 2
print(x)
>>>>>>>
1 ###### 这个的只是定义函数阶段,全局变量找值,如果没有就报错 不会去找局部变量的名称空间
在定义阶段的,提前给形参复制的操作就是默认值参数
x= 1
def index(arg = x):######arg 已经给赋值给1 下面的不会动
'''
看全局名空和局部明空的区别
'''
print(x)
print(arg)#####只有掉用函数的时候,index(有值传入才可以把默认的arg = x,进行修改)
x = 2 ##### x被从新赋值给2
index()
>>>>>>>
2
1
另外一个例子
x = 1
def index():
'''
全局名称空间
'''
def wrapper():
print(x)
return wrapper#####return 在index函数的下方,所有返回的wrapper给了f,f =wrapper ,wrapper()执行wrapper的函数
f = index()
f()
>>>>>>
1
五、作用域的分类
作用域:
名称空间的作用范围
作用域的分类:
1、全局作用域
-全局可以调用的名字就存在于全局作用域
-只要程序一直执行,永久存活,若程序结束,则销毁
内置名称空间+全局名称空间
2、局部作用域
局部可以调用的名字就存放与局部作用域
-局部的名称空间+局部的局部名称空间、
-只要程序一直执行,调用函数时存活,结束时销毁。
局部名称空间
global:声明全局变量(***)
nonlocal:在局部名称空间声明局部变量,在局部修改上层函数的变量(*)
只有可变类型可以在局部修改外部变量的值 (*****)
全局变量的举例
def index():
# global x
x = 2 ######x = 2 是局部变量名空 不能被全局的x(print(x))的调用
print()
index()
print(x)
>>>>>>>>
print(x)
NameError: name 'x' is not defined
修正后
def index():
global x ######声明了x为全局的变量名称空间
x = 2
print()
index()
print(x)
>>>>>>>
2
nonlocal
def index():
'''
nonlocal ####在局部的名称空间声明局部变量
'''
x = 1
def func():
nonlocal x
x = 2
func()
print(x)###如果没有nonlocal 打印出来的结果是1
index()
>>>>>>>
2
x = 1
def func():
def wrapper():
global x ####这个声明了修改x = 1 全局变量 所以打印结果x = 2
x = 2
wrapper()
print(x)
func()
>>>>>>>>>
2
######只有可变类型可以在局部修改外部变量的值 (*****)
l1 = []
def index(a):
'''
可变的列表比较特殊
'''
l1.append(a)
#print(l1)
index(1)
print(l1)
>>>>>>>
[1]
局部变量的修改无法影响上层,上上层
def index():
x = 1
def index2():
nonlocal x
x = 2
index2()
print(x)####如果没有nonlocal 打印的结果就是1
index()
>>>>>>>>
2
局部变量的修改无法影响上层,上上层
x = 111
def index():
x = 1
def func2():
x = 2
def func():
nonlocal x
x = 3
func()
print(x)###因为在局部名称空间声明了局部变量,在局部修改上层函数的变量
func2()
print(x)
index()
print(x)
>>>>>>
3
1
1111