命名空间、全局/局部作用域、作用域链、闭包

命名空间:3种

内置命名空间 —— python解释器
  就是python解释器一启动就可以使用的名字(input、print ...)存储在内置命名空间中
  内置的名字在启动解释器的时候被加载进内存里

全局命名空间 —— 我们写的代码但不是函数中的代码
  是在程序从上到下被执行的过程中依次加载进内存的
  放置了我们设置的所有变量名和函数名

局部命名空间 —— 函数内写的代码
  就是函数内部定义的名字
  当调用函数的时候,才会产生命名空间,随着函数执行的结束,这个命名空间就又消失了

在局部:可以使用全局、内置命名空间中的名字
在全局:可以使用内置命名空间中的名字,不可以用局部命名空间的名字
在内置:没有局部和全局命名空间的名字

注意:当我们在全局定义了和内置命名空间中同名的名字时,会使用全局的名字

print = "xx"
print(print)

Traceback (most recent call last):
  File "E:/LearnPython/review/test.py", line 4, in <module>
    print(print)
TypeError: 'str' object is not callable

作用域:2种

全局作用域:作用在全局 —— 内置和全局命名空间中的名字都属于全局作用域 globals()
局部作用域:作用在局部 —— 函数(局部命名空间中的名字属于局部作用域)locals()

对于不可变数据类型,在局部可以查看全局作用域中的变量,但是不能直接修改。
如果想要修改,需要在程序的一开始添加global声明(尽量避免使用global,不安全,会对全局产生影响)
如果在一个局部(函数)内声明了一个global变量,那么这个变量在局部的所有操作将对全局的变量有效。

例如:

a = 1
def func():
    global a  # 声明
    a += 1    # 对a进行操作
    print(a)  # 2

func()

print(a)  # 2
#报错 UnboundLocalError: local variable 'a' referenced before assignment
a = 1
def func():
    a += 1
    print(a)

func()

globals() 与 locals()

globals()  永远打印全局的名字
locals()    输出什么是根据locals所在的位置

a = 1

def func():
    b = 2
    print(locals())
    print(globals())
    
func()
print(globals())
print(locals())

函数的嵌套调用

def max1(a, b):
    return a if a > b else b

def max2(x, y, z):
    ret1 = max1(x, y)  # 函数调用,用ret1接收返回值
    return max1(ret1, z)  # 再次调用,用ret2接收返回值

ret2 = max2(1, 2, 3)
print(ret2)  # 3

nonlocal:只能用于声明局部变量,找上层中离当前函数最近一层的局部变量
注意:声明了nonlocal的内部函数的变量修改会影响到离当前函数最近一层的局部变量

a = 10
def outer():
    a = 20
    def inner1():
        b = 30
        def inner2():
            nonlocal a
            a += 1  # 修改变量a,对局部(有关联的最近一层)有影响,对全局没影响
            print("局部第三层:", a)
        inner2()
        print("局部第二层:", b)
    inner1()
    print("局部第一层", a)
    
outer()
print("全局 :", a)

作用域链:使用变量的时候,先从自己的名字空间找,找不到就向外一层一层地找,直到找到为止,找不到就报错。

函数名:

  1. 函数名可以赋值给一个变量
  2. 函数名可以作为容器类型的元素
  3. 函数名可以作为函数的返回值
  4. 函数名可以作为另一个函数的参数
def func():
    print(123)

func()  # 函数名就是内存地址
func_ = func  # 函数名可以赋值
func_()

l = [func, func_]  # 函数名可以作为容器类型的元素
print(l)

for i in l:
    i()

def func1():
    print(123)  # 123

def func2(f):
    f()
    return f  # 函数名可以作为函数的返回值

func3 = func2(func1)  # 函数名可以作为另一个函数的参数
func3()  # 123

闭包:是一个嵌套函数,内部函数调用外部函数的变量

def outer():
    name = "ppd"
    def inner():
        print(name)  # 内部inner函数调用了外部outer函数的变量name
    print(inner.__closure__)

outer()

打印一个函数的closure,有cell就证明是一个闭包。

闭包最常见的用法,在函数的外部去使用它内部的函数。

def outer():
    name = "ppd"
    def inner():
        print(name)
    return inner

func = outer()
func()  # ppd
print(func.__name__)  # inner
print(func.__closure__)  # (<cell at 0x0000000000695D68: str object at 0x00000000010AB378>,)

 

posted @ 2018-08-31 17:25  就俗人一个  阅读(343)  评论(0编辑  收藏  举报