函数的对象,嵌套,名称空间day10
今日学习总结:
一、函数对象:是指函数可以被当做数据来处理
ps:传参的时候没有特殊需求,一定不要加括号,加括号当场执行了
def index(): print('hello') index() print(index) # 输出的 就是函数index 的对象
结果:
hello
<function index at 0x0000000001FF2E18>
1.函数名可以被引用
def add(x,y): return x,y #表示返回的 是一个元组 func = add #表示函数名可以被引用 print(func(1,2))
2.函数名可以作为容器类型的元素
def func(): print('hello word') l1 = [1,'w',func,func()] # func是函数名,func()是调用函数 f = l1[2] # 表示取出func print(f) #表示输出func 的对象 结果: hello word <function func at 0x0000000009EE27B8>
3.函数名可以当做参数传递
def foo(x, y, func): #定义形参 print(x, y) func() # 这里的func()等于bar() def bar(): print('hello world') foo(1, 2, bar) # 把函数名bar 传给func 结果: 1 2 hello worl
4.函数名可以当做返回值使用
def index(): print('hello world') def func(a): return a s=func(index) #把函数名index传给a 然后赋给s 这时 s就是index 了 s() 结果: hello world
ps:重, 函数名可以当做返回值使用
x=111 def index(): print(x) def wrapper(): print(x) return wrapper # 表示是返回值给了f x=222 f=index() f()
二、名称空间:存放名字与对象映射/绑定关系的地方。
1.内建名称空间: 伴随着python解释器的启动/关闭而产生/回收。所以内建名称空间是第一个被加载的名称空间,用来存放一些内置的名字,比如内建函数名。
python提前给你的定义完的名字,就是存在内置名称空间
这些 print int list 都是内建名称 print(print) print(int) print(list) 结果:
<built-in function print>
<class 'int'>
<class 'list'>
2.全局名称空间:伴随python文件的开始执行/执行完毕而产生/回收,是第二个被加载的名称空间,文件执行过程中产生的名字都会存放于全局名称空间中。
存放文件级别的名字,就是全局名称空间。 if while for 内部定义的名字执行之后都存放于全局名称空间
x=1
print(x)
x=1 def index(): print(x) index()
3.局部名称空间:伴随函数的调用/结束而临时产生/回收。函数的形参、函数内定义的名字都会被存放于局部名称空间中。
函数内部定义的所有名字都是存放与当前函数的内置名称空间
def index(): x=1 print(x) index
def index(): x=1 index() print(x) # 不能这样写 因为x=1局部变量,print()中的x 没有被定义 修改为: x=2 def index(): x=1 index() print(x) 结果:2 因为x=1是局部变量 不能输出
三、作用域
1.全局作用域:位于全局名称空间、内建名称空间中的名字属于全局范围,该范围内的名字全局存活(在整个文件执行过程中)、全局有效(在任意位置都可以使用)
全局可以调用的名字就存在于全局作用域:内置名称空间+全局名称空间
2.局部作用域:位于局部名称空间中的名字属于局部范围。该范围内的名字临时存活(在函数调用时临时生成,函数调用结束后就释放)、局部有效(只能在函数内部使用)
局部可以调用的名字就存放于局部作用域:局部名称空间
3.global:声明全局变量,当想要改变不可变类型的变量时,可以用global
x = 1 def index(): global x #声明x=2是全局变量 x = 2 index() print(x) # 2
例子:
b = 6 def test3(a): global b print(a) print(b) # 当函数执行到这一步仍然会报错 # UnboundLocalError: local variable 'b' referenced before assignment b = 9 # 比示例二多了一行赋值 print(b) test3(1)
结果:
1
6
9
4.nonlocal:在局部名称空间声明局部变量,在局部修改上层函数的变量。
x=111
def index():
x = 1
def func2():
x = 2
def func():
x = 3 # 这里x=3是灰色的,因为它是局部变量,没有被用到。
func()
print(x) # 这里x=3是灰色的,因为它是局部变量,没有被用到。所以打印的结果是 2
func2()
print(x)
index()
print(x)
结果:
2
1
111
使用nonlocal
x=111 def index(): x = 1 def func2(): x = 2 def func(): nonlocal x #在这里声明了x=3,则会改变上层的变量的值 x = 3 func() print(x) #在这里声明了x=3,则会改变上层的变量的值,输出结果为:3 func2() print(x) index() print(x)
结果:
3
1
111
ps :只有可变类型可以在局部修改外部变量的值
l1 = [] #l1是列表 是可变类型 ,如果换成不可变类型的元组就错了 def index(a): l1.append(a) # 表示给列表l1添加值,改变列表 index(2) print(l1)
四、名称空间的查找顺序:
1.在局部作用域查找名字时,因为起始位置是局部作用域,所以查找顺序为:局部名称空间--全局名称空间--内置名称空间
x=100 #全局作用域的名字 def foo(): x=300 #局部作用域的名字 print(x) #在局部找x foo() #结果:300
2.在全局作用域查找名字时,因为起始位置是全局作用域,所以查找顺序为:全局名称空间--内置名称空间。
ps: 在全局作用域查找名字时,不会取局部作用域中的局部名称空间去找
x=100 #全局作用域的名字 def foo(): x=300 #局部作用域的名字, print(x) #在全局找x foo() #结果:100
五、生命周期:
1.内置名称空间的生命周期:
在python解释器启动时生效,关闭解释器的时候就消失。
2.全局名称空间的生命周期:
当你启动这个py文件时生效,当前页面 代码执行结束之后失效
3.局部名称空间的生命周期:
当你调用当前函数时生效,函数体最后一行代码执行结束就失效
def index(): x=1 return x print(index) def foo(): print(index) foo() 结果: <function index at 0x0000000009EE27B8> <function index at 0x0000000009EE27B8>
六、特殊例子:
ps:函数内部使用的名字,在定义阶段已经定死了,与你的调用位置无关
x=1 def index(arg=x): # 在这里把x=1的值给了arg , arg=x是默认参数 print(x) # 在局部找 print(arg) x=2 index() 结果: 2 1