函数进阶
1、函数命名空间和作用域
命名空间一共分为三种:
全局命名空间
局部命名空间
内置命名空间
*内置命名空间中存放了python解释器为我们提供的名字:input , print , str , list , tuple...
三种命名空间之间的加载与取值顺序:
加载顺序:内置命名空间(程序运行前加载)->全局命名空间(程序运行中:从上到下加载)->局部命名空间(程序运行中:调用时才加载)
取值顺序:
在局部调用:局部命名空间->全局命名空间->内置命名空间
在全局调用:全局命名空间->内置命名空间
综上所述,在找寻变量时,从小范围,一层一层到大范围去找寻。
作用域
作用域就是作用范围,按照生效范围可以分为全局作用域和局部作用域。
全局作用域:包含内置名称空间、全局名称空间,在整个文件的任意位置都能被引用、全局有效
局部作用域:局部名称空间,只能在局部范围内生效
globals和locals方法:
global 关键字:
1、声明全局变量;
2、在局部作用域对全局作用域的全局变量进行修改,只适用于字符串和数字
## 变量为字符串或数字,需要global声明变量
2 b = 1 3 def func(): 4 global b ## 将局部变量 b 申明成全局变量 5 b = 13 6 return b 7 8 print(func())
运行结果:13
## 变量为非字符串和数字,可以直接修改全局变量
12 b = [1,2,3] 13 def func(): 14 b = [4,5,6] 15 return b 16 17 print(func())
运行结果:
[4,5,6]
nonlocal 关键字:
1、不能修改全局变量;
2、在局部作用域中,对父级作用域(或者更外层的作用域非全局作用域)的变量进行引用和修改,此层及以下的变量全部发生改变。
1 b = 1 ## 全局变量 2 def func1(): 3 b = 2 4 print(b) ## b = 2 5 def func2(): 6 nonlocal b ## 引用上一级的变量 b 7 print(b) ## b = 2 8 def func3(): 9 print(b) ## b = 2 10 11 12 func3() 13 func2() 14 func1() 15 print(b)
运行结果:
2
2
2
1
2、函数名 === 第一类对象
1) 函数名的内存地址 3 def func(): 4 print(11) 5 print(func) ## <function func at 0x0000000002FFC158>
6 print(id(func)) ## 50315608 函数的内存地址
运行结果:
<function func at 0x0000000002FFC158>
50315608
2) 函数名赋值给其他变量 11 def func(): 12 ## 将函数名func赋值给func1 13 print(11) 14 func1 = func 15 func1()
运行结果:
11
3) 函数名可以当做容器内的元素(循环执行函数) 20 def func1(): 21 print(11) 22 def func2(): 23 print(22) 24 def func3(): 25 print(33) 26 def func4(): 27 print(44) 28 list = [func1,func2,func3,func4] 29 for i in list: 30 i()
运行结果:
11
22
33
44 4) 函数名可以当做函数的参数 37 def func1(): 38 print(111) 39 def func2(a): 40 pass 41 func2(func1())
运行结果:
111 5) 函数名可以当做函数的返回值 46 def func1(): 47 print(111) 48 def func2(a): 49 return a 50 func2(func1())
运行结果:
111
3、闭包
闭包:内层函数对外层函数(非全局)的变量的引用 1)闭包函数 5 a = 1 6 def func1(): 7 b = 2 8 def func2(): 9 c = b ### 内层函数引用非全局的外层函数变量,是闭包函数 10 return c 11 ret = func2() 12 print(ret) 13 print(func2.__closure__) 14 func1()
运行结果:
2
(<cell at 0x0000000002D87498: int object at 0x000000001D62EC90>,)
2)非闭包函数 18 a = 1 19 def func1(): 20 b = 2 21 def func2(): 22 print(a) ### 内存函数引用全局变量,不是闭包函数 23 func2() 24 print(func2.__closure__) 25 func1()
运行结果:
1
None
3)检测是否为闭包函数 29 def func1(x): 30 def func2(): ### func2 为闭包函数 31 return x 32 ret = func2() 33 print(ret) 34 print(func2.__closure__) ### 检测函数是否是闭包函数(返回cell就是闭包函数,返回none则不是闭包) 35 func1(1) 运行结果:
1
(<cell at 0x0000000002BF7498: int object at 0x000000001D5CEC70>,)
4)闭包函数的应用 40 def wrapper(): 41 money = 1000 42 def func(): 43 name = "eva" 44 def inner(): 45 print(name,money) 46 return inner() 47 return func() 48 f = wrapper()
运行结果:
eva 1000
5)闭包的用处:若内存函数是个闭包,python内部有个机制, 遇到闭包,会在内存中开启一个内存空间,不会随着函数的结束而关闭 54 from urllib.request import urlopen 55 56 def pachong(url): 57 content = urlopen(url).read() 58 def get(): ### 通过闭包函数的特性节俭资源 59 with open("爬虫","ab") as f: 60 f.write(content) 61 return get ### 执行内层函数 62 pachong("https://www.cnblogs.com/")()
6)拓展 1、执行内层函数的两种方式:
1)返回内层函数的函数值 70 def wrapper(): 71 def inner(): 72 print(66) 73 return inner 74 wrapper()() # 执行顺序:先调用函数wrapper(),返回 inner,再调用函数inner(),打印内部函数inner()
运行结果:
66
2)直接调用内部函数 82 def wrapper(): 83 def inner(): 84 print(66) 85 inner() 86 wrapper()
运行结果:
66