# 1. 命名空间
## 1.1 命名空间的种类
命名空间共有有三种
1) 内置命名空间 —— python解释器
就是python解释器一启动就可以使用的名字存储在内置命名空间中
内置的名字在启动解释器的时候被加载进内存里
<br>
2) 全局命名空间 —— 我们写的代码但不是函数中的代码
是在程序从上到下被执行的过程中依次加载进内存的
放置了我们设置的所有变量名和函数名
<br>
3) 局部命名空间 —— 函数
就是函数内部定义的名字
当调用函数的时候,才会产生这个名称空间,随着函数执行的结束,这个命名空间就又消失了。
<br>
## 1.2 三种命名空间之间的加载与取值顺序
加载顺序:内置命名空间(程序运行前加载)->全局命名空间(程序运行中:从上到下加载)->局部命名空间(程序运行中:调用时才加载)
* 在局部:可以使用全局、内置命名空间中的名字
* 在全局:可以使用内置命名空间中的名字,但是不能用局部中使用
* 在内置:不能使用局部和全局的名字的
<br>
## 1.3 命名空间的其他说明
1) 在正常情况下,直接使用内置的名字
2) 当我们在全局定义了和内置名字空间中同名的名字时,会使用全局的名字
3) 当我自己有的时候 我就不找我的上级要了
4) 如果自己没有,就找上一级要,上一级没有再找上一级,如果内置的名字空间都没有,就报错
5) 多个函数应该拥有多个独立的局部名字空间,不互相共享
范例1:(对应1、2、3、4)
```python
def max(l):
print("in max func")
print(max([1,2,3]))
```
执行结果
```
in max func
None
```
<br>
范例2:(对应4)
```
def input():
print("in inpput now")
def func():
input()
func()
```
执行结果
```
in inpput now
```
<br>
范例3:(对应4)
```python
def input():
print("in inpput now")
def func():
input = 1
print(input)
func()
```
执行结果
```
1
```
<br>
范例4:(对应5)
```python
def fun1():
a = 1
def func2():
print(a)
print(func2())
```
执行结果
```
Traceback (most recent call last):
File "E:/python_project/S9/hello.py", line 8, in <module>
print(func2())
File "E:/python_project/S9/hello.py", line 6, in func2
print(a)
NameError: name 'a' is not defined
```
----------
# 2 作用域
## 2.1 作用域的种类
作用域共两种
1) 全局作用域 —— 作用在全局 —— 内置和全局名字空间中的名字都属于全局作用域 —— globals()
范例1:
```python
a = 1
def func():
print(a)
func()
```
执行结果:
```
1
```
<br>
* 对于不可变数据类型,在局部可以查看全局作用域中的变量,但是不能直接修改
* 如果想要修改,需要在程序的一开始添加global声明
* 如果在一个局部(函数)内声明了一个global变量,那么这个变量在局部的所有操作将对全局的变量有效
范例2:global关键字(但使用global方式不安全,尽量少用)
```python
a = 1
def func():
global a
a += 1
func()
print(a)
```
执行结果:
```
2
```
<br>
2) 局部作用域 —— 作用在局部 —— 函数(局部名字空间中的名字属于局部作用域) —— locals()
<br>
## 2.2 作用域的方法两则(不常用)
globals() 永远打印全局的名字
locals() 输出什么 根据locals所在的位置,在全局输出全局,在局部输出局部
范例:
```python
a = 1
b = 2
def func():
x = "aaa"
y = "bbb"
print(locals())
func()
print(globals())
```
执行结果:
```
{'x': 'aaa', 'y': 'bbb'}
{'a': 1, '__package__': None, '__builtins__': <module 'builtins' (built-in)>, '__spec__': None, '__file__': 'D:/temp_study/python01/test.py', '__loader__': <_frozen_importlib.SourceFileLoader object at 0x0000000003C64D68>, 'b': 2, '__name__': '__main__', 'func': <function func at 0x000000000331CB70>, '__doc__': None, '__cached__': None}
```
----------
# 3 函数的嵌套与作用域链
## 3.1 函数的嵌套调用
范例:
```python
def my_max(a,b):
return a if a > b else b
def three_max(x,y,z): # 函数的嵌套调用
c = my_max(x,y)
return my_max(c,z)
print(three_max(1,2,3))
```
执行结果
```
3
```
<br>
## 3.2 函数的嵌套定义
1) 函数嵌套定义的正常流程
范例:
```python
def outer(): # 第一步
def inner(): # 第三步
print("inner") # 第五步
inner() # 第四步
outer() # 第二步
```
执行结果
```
inner
```
<br>
2) 内部函数可以使用外部函数的变量
范例:
```
def outer():
a = 1
def inner():
print(a)
print("inner")
inner()
outer()
```
执行结果
```
1
inner
```
<br>
3) 三层嵌套
范例1:
```
def outer():
a = 1
def inner():
print(a)
print("inner")
def inner2():
print("inner2")
inner2()
inner()
outer()
```
执行结果:
```
1
inner
inner2
```
<br>
范例2:
```python
def outer():
a = 1
def inner():
b = 2
print(a)
print("inner")
def inner2():
print(a,b)
print("inner2")
inner2()
inner()
outer()
```
执行结果:
```
1
inner
1 2
inner2
```
<br>
### 3.2.1 nonlocal()
nonlocal 只能用于局部变量 找上层中离当前函数最近一层的局部变量。
声明了nonlocal的内部函数的变量修改会影响到离当前函数最近一层的局部变量。
对全局:无效
对局部:也只是对最近的一层有影响
范例1:
```
a = 1 # 这是全局变量
def outer():
a = 1 # 这是局部变量
def inner():
b = 2
print(a)
print("inner")
def inner2():
nonlocal a # 声明了一个上面第一层局部变量(离它最近的局部变量)
a += 1 # 不可变数据类型的修改
print("inner2")
inner2()
inner()
print("**a** :",a)
outer()
print("全局:",a)
```
执行结果
```
1
inner
inner2
**a** : 2
全局: 1
```
<br>
范例2:
```python
a = 1
def outer():
a = 1
def inner():
a = 2
print(a)
print("inner")
def inner2():
nonlocal a
a += 1
print("inner2")
inner2()
print("##a##:",a)
inner()
print("**a** :",a)
outer()
print("全局:",a)
```
执行结果
```
2
inner
inner2
##a##: 3
**a** : 1
全局: 1
```
<br>
范例3:
```python
a = 0
def outer():
# a = 1
def inner():
a = 2
def inner2():
nonlocal a
print(a)
inner2()
inner()
outer()
```
执行结果
```
2
```
<br>
## 3.3 作用域链
在内部函数使用变量的时候,是从小局部到大局部到全局到内置名字的过程一级一级往上找,找到最近的一个就使用----作用域链
范例1:
```python
def f1():
a = 1
def f2():
print(a)
f2()
f1()
```
执行结果:
```
1
```
<br>
范例2:
```python
def f1():
a = 1
def f2():
def f3():
print(a)
f3()
f2()
f1()
```
执行结果:
```
1
```
<br>
范例3:
```python
def f1():
a = 1
def f2():
a = 2
f2()
print('a in f1 : ',a)
f1()
```
执行结果:
```
a in f1 : 1
```
----------
# 4 函数名的本质
函数名本质上就是函数的内存地址
范例1:可以被引用
```python
def func():
print(123)
# func() #函数名就是内存地址
func2 = func # 函数名可以赋值
func2()
```
执行结果
```
123
```
<br>
范例2:可以被当作容器类型的元素
```python
def func():
print(123)
func2 = func
func2()
l = [func,func2] # 函数名可以作为容器类型的元素
print(l)
for i in l:
i()
```
执行结果
```
123
[<function func at 0x000002604CB969D8>, <function func at 0x000002604CB969D8>]
123
123
```
<br>
范例3:可以当作函数的参数
```python
def func():
print(123)
def wahaha(f):
f()
wahaha(func) # 函数名可以作为函数的参数
```
执行结果
```
123
```
<br>
范例4:可以当作函数的返回值
```
def func():
print(123)
def wahaha(f):
f()
return f #函数名可以作为函数的返回值
qqxing = wahaha(func) # 函数名可以作为函数的参数
qqxing()
```
执行结果
```
123
123
```
`不明白?那就记住一句话,就当普通变量用`
第一类对象(first-class object)指
1.可在运行期创建
2.可用作函数参数或返回值
3.可存入变量的实体。
----------
# 5 闭包(函数)
闭包:嵌套函数,内部函数调用外部函数的变量
```python
def outer():
a = 1
def inner():
print(a)
```
<br>
## 5.1 闭包的常用形式
```python
def outer():
a = 1
def inner():
print(a)
return inner
inn = outer()
inn()
```
执行结果
```
1
```
<br>
## 5.2 \__closure\__
判断闭包函数的方法__closure__
范例:
```python
def outer():
a = 1
def inner():
print(a)
print(inner.__closure__)
outer()
print(outer.__closure__)
```
执行结果:
```
(<cell at 0x00000000026C02E8: int object at 0x000000005BB180C0>,) # 输出的__closure__有cell元素 :是闭包函数
None # 输出的__closure__为None :不是闭包函数
```
<br>
## 5.3 闭包函数的模拟案例
不闭包的案例:
```python
from urllib.request import urlopen
ret = urlopen("https://www.baidu.com").read()
print(ret)
```
执行结果:
```
b'<html>\r\n<head>\r\n\t<script>\r\n\t\tlocation.replace(location.href.replace("https://","http://"));\r\n\t</script>\r\n</head>\r\n<body>\r\n\t<noscript><meta http-equiv="refresh" content="0;url=http://www.baidu.com/"></noscript>\r\n</body>\r\n</html>'
```
<br>
闭包案例:
```python
from urllib.request import urlopen
def get_url():
url = "https://www.baidu.com"
def get():
ret = urlopen(url).read()
print(ret)
return get
get_func = get_url()
get_func()
```
执行结果:
```
b'<html>\r\n<head>\r\n\t<script>\r\n\t\tlocation.replace(location.href.replace("https://","http://"));\r\n\t</script>\r\n</head>\r\n<body>\r\n\t<noscript><meta http-equiv="refresh" content="0;url=http://www.baidu.com/"></noscript>\r\n</body>\r\n</html>'
```