函数的命名空间
命名空间一共分为三种:
- 内置命名空间 —— Python解释器
- 就是python解释器一启动就可以使用的名字存储在内置命名空间中
- 内置的名字在启动解释器的时候被加载进内存里
print() 、len()、list、tuple等
- 全局命名空间 —— 我们写的代码但不是函数中的代码
- 是在程序从上到下被执行的过程中依次加载进内存的
- 放置了我们设置的所有变量名和函数名
- 局部命名空间 —— 函数
- 就是函数内部定义的名字
- 当调用函数的时候,才会产生这个名称空间,随着函数执行的结束,这个命名空间又消失了
注意:
- 在局部:可以使用全局、内置命名空间中的名字
- 在全局:可以使用内置命名空间中的名字,但是不能用局部的
- 在内置:不能使用局部和全局的名字的
命名空间的使用
全局不能访问局部
1 2 3 4 5
| def func(): a = 1
func() print(a) # 报错 a为 func函数内部定义的变量为局部变量,不能在全局中访问
|
内置和全局都存在的max方法
这个非常神似js的作用域链
- max为系统定义过的
- 你在全局里重新定义max
- 调用的时候就会使用全局里定义的(就近原则)
1 2 3 4
| def max(l): print('in max func')
print(max([1,2,3]))
|
python的关怀
- func –> 函数的内存地址
- 函数名() 函数的调用
- 函数的内存地址() 函数的调用
1 2 3 4
| def xxx(): print(1)
print(xxx) # 打印出一个地址 <function xxx at 0x00000000004D2E18>
|
通过函数名调用明显比 调用形如「0x00000000004D2E18 」的十六进制数表示的内存地址要快。
(在一个班级的环境中:你是选择用人名来产生会话?还是身份证号。)
xxx函数的调用过程
- xxx() 的时候
- 会现在全局范围内找有没有 xxx的定义,有则调用,反之去它的上一层也就是 内置命名空间,有则调用,反之报错
作用域
作用域的种类
- 全局作用域 —— 作用在全局 —— 内置和全局名字空间中的名字都属于全局作用域 ——globals()
注:永远打印全局的名字
- 局部作用域 —— 作用在局部 —— 函数(局部名字空间中的名字属于局部作用域) ——locals()
注:输出什么,根据locals所在的位置(根据调用位置来输出结果)
1 2 3
| print(globals()) print(locals()) # 结果一样 因为都在全局作用域里
|
1 2 3 4 5 6 7 8 9 10
| def func(): a = 12 b = 20 print(locals()) print(globals())
func() # 结果不一样 # globals在哪里调用都是输出全局作用域里的内容 # locals 这里只有 {'a': 12 , 'b': 20}
|
global关键字的作用
- 对于不可变数据类型,在局部可查看全局作用域中的变量,但是不能直接修改
- 如果想要修改的时候影响到全局,需要在程序的一开始添加global声明
- 如果在一个局部(函数)内声明了一个global变量,那么这个变量在局部的所有操作将对全局的变量有效
不修改的情况下可以直接访问全局作用域的变量
1 2 3 4 5
| a = 1 def xxx(): print(a)
xxx() # 1
|
修改全局变量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| a = 1 def xxx(): a = 2 print(a)
xxx() # 2 print(a) # 1
# 影响到全局 b = 1 def xxx(): global b b = 2 print(b)
xxx() # 2 print(b) # 2
|
函数的嵌套和作用域链
1.函数的嵌套调用
1 2 3 4 5 6 7 8
| def max(a,b): return a if a>b else b
def the_max(x,y,z): #函数的嵌套调用 c = max(x,y) return max(c,z)
print(the_max(1,2,3))
|
2.函数的嵌套定义
1 2 3 4 5 6 7
| def f1(): print("f1") def f2(): print("f2") f2()
f1()
|
3.函数的作用域链
初学让你疑惑的执行结果!!! 尤其是你会js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| def f1(): a = 1 def f2(): a = 2 f2() print('a in f1 : ',a)
f1() # a in f1 : 1
''' f2中修改了 局部变量 a 的值 但是 在 f1中a值仍然为 1
ps : js里这个肯定是 2 '''
|
原来python里要加 nonlocal 声明
1 2 3 4 5 6 7 8 9
| def f1(): a = 1 def f2(): nonlocal a a = 2 f2() print('a in f1 : ',a)
f1() # a in f1 : 2
|
nonlocal
首先,要明确 nonlocal 关键字是定义在闭包里面的。请看以下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| x = 0 def outer(): x = 1 def inner(): x = 2 print("inner:", x)
inner() print("outer:", x) outer() print("global:", x)
结果: inner: 2 outer: 1 global: 0
|
现在,在闭包里面加入nonlocal关键字进行声明:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| x = 0 def outer(): x = 1 def inner(): nonlocal x x = 2 print("inner:", x)
inner() print("outer:", x) outer() print("global:", x)
结果: inner: 2 outer: 2 global: 0
|
区别:一个函数里面嵌套了一个函数。当使用 nonlocal 时,就声明了该变量不只在嵌套函数inner()里面才有效, 而是在整个大函数里面都有效。
我们在看 global
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| x = 0 def outer(): x = 1 def inner(): global x x = 2 print("inner:", x)
inner() print("outer:", x) outer() print("global:", x)
结果: inner: 2 outer: 1 global: 2
|
结论:global 是对整个环境下的变量起作用,而不是对函数类的变量起作用。
4.函数的本质
可以被引用
1 2 3 4 5
| def func(): print('in func')
f = func print(f)
|
可以被当作容器类型的元素
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| def f1(): print('f1')
def f2(): print('f2')
def f3(): print('f3')
l = [f1,f2,f3] d = {'f1':f1,'f2':f2,'f3':f3} #调用 l[0]() d['f2']()
|
可以当作的参数和返回值
1 2 3 4 5 6 7 8 9
| def func(): print(123)
def wahaha(f): f() return f #函数名可以作为函数的返回值
qqxing = wahaha(func) # 函数名可以作为函数的参数 qqxing()
|
5.闭包
嵌套函数,内部函数调用外部函数的变量
常用方式
1 2 3 4 5 6 7 8
| def func(): name = 'eva' def inner(): print(name) return inner
f = func() f()
|
判断闭包函数的方法 closure
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| #输出的__closure__有cell元素 :是闭包函数 def func(): name = 'eva' def inner(): print(name) print(inner.__closure__) return inner
f = func() f()
结果: (<cell at 0x0000000001ECA4C8: str object at 0x0000000001DCB1B8>,) eva -------------------------华丽的分割线-------------------------------------------------------------- #输出的__closure__为None :不是闭包函数 name = 'egon' def func2(): def inner(): print(name) print(inner.__closure__) return inner
f2 = func2() f2()
结果: None egon
|
- 闭包嵌套
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| def wrapper(): money = 1000 def func(): name = 'eva' def inner(): print(name,money) return inner return func
f = wrapper() i = f() i()
结果: eva 1000
|
- 闭包函数获取网络应用
1 2 3 4 5 6 7 8 9 10 11
| from urllib.request import urlopen
def index(): url = "http://www.xiaohua100.cn/index.html" def get(): return urlopen(url).read() return get
xiaohua = index() content = xiaohua() print(content)
|