函数基础二 -- 命名空间,作用域,闭包

1. 命名空间

1.1内置命名空间

就是python解释器一启动,就可以使用的名字存储在内置命名空间中

print() input() len() tuple list ···

内置的名字在启动解释器的时候被夹在进内存里

1.2全局命名空间

在程序从上到下被执行的过程中一次加载进内存的

放置了我们设置的所有变量名和函数名

1.3局部命名空间

是函数内部定义的名字

当调用函数的时候,才会产生这个命名空间,随着函数执行的结束,这个命名空间就消失了

  在局部: 可以使用全局、内置命名空间中的名字
  在全局: 可以使用内置命名空间中的名字,但是不能用在局部中使用
  在内置: 不能使用局部和全局的名字
  在正常情况下, 直接使用内置的名字
  当我们在全局定义了和内置名字空间中同名的名字时,会使用全局的名字
  (当我自己有的时候,我就不找我的上级要了)
  如果自己没有,就找上一级要,上一级没有再找上一级,如果内置的命名空间都没有,就报错
  局部空间的变量名字是不共享的,各局部空间是隔离的
  多个函数应该拥有多个独立的局部名字空间,且不共享

函数基础二 -- 命名空间,作用域,闭包函数基础二 -- 命名空间,作用域,闭包

Tip:
func()
func - --> 函数的内存地址
func() - - > 函数的调用
即:
函数的内存地址 + () - --> 函数的调用
2. 作用域

    全局作用域 ---作用在全局 --- 内置和全局名字空间中的名字都属于全局作用域 ---使用globals()函数查看
    局部作用域 ---作用在局部 --- 函数(局部名字空间中的名字属于局部作用域) ---使用locals()函数查看
a = 1
def func():
    global a
    a += 1
func()
print(a)
对于不可变数据类型,在局部可以查看全局作用域中的变量
但是不能直接修改
如果想要修改,需要在程序的一开始添加global声明
如果在一个局部(函数)内声明了一个global变量,那么这个变量在局部的所有操作将对全局的变量有效

举例:

a = 1
def func():
    # global a
    a += 1       # 不可变数据类型的更改
func()
print(a)      # 结果报错:UnboundLocalError: local variable 'a' referenced before assignment(使用之前没有定义), 因为python命名空间的原因

 Tip:

关于  globals()永远打印全局的名字
      locals()根据locals所在位置进行输出

 3. 函数的嵌套定义

def outer():
    def inner():
        print('inner')
    inner()
outer()
a = 1
def outer():
    a = 2
    def inner():
        print(a)
        print('inner')
        def inner2():
            nonlocal a      # 声明了一个上层局部变量(找上层离当前函数最近一层的局部变量)
a += 1 # 不可变数据类型的更改
     print('inner2')
     inner2()
inner()
print('**a**',a)
outer()
print('全局a',a)
# 对全局无效
# 对局部,也只是对最近的一层有影响
a = 0
def outer():
    def inner():
        def inner2():
            nonlocal a
            print(a)
        inner2()
    inner()

outer()

 4. 函数的本质

  函数名    就是第一类对象

def func():
    print(123)
func()     # 函数名就是内存地址
func2 = func     # 函数名可以赋值
func2()

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

def wahaha(f):
    f()
    return f
qqxing =  wahaha(func)   # 函数名可以作为函数的参数

 5. 闭包

定义 :   1. 嵌套函数       2. 内部函数调用外部函数的变量

def outer():
    a = 1
    def inner():
        print(a)
    print(inner.__closure__)     # 打印cell ···的内容,说明这个函数就是闭包
outer()
print(outer.__closure__)
     #  结果: (<cell at 0x0000006FEADFC078: int object at 0x000000005E9D22D0>,)
     #         None

闭包最常用的形式:

# 在一个函数的外部调用这个函数内部的函数
def outer():
    a = 1
    def inner():
        print(a)
    return inner
inn = outer()
inn()

闭包实例:

from urllib.request import urlopen
def get_url():
    url = 'http://www.baidu.com/'     # 这样每次执行,内存里不需要多次定义url,节省资源
    def get():
        ret = urlopen(url).read()
    return ret

get_func = get_url()
get_func()

6.  排错

出现多行错误提示,要从下往上找
如果最下边提示的是自己写的代码,那么错误就在这个地方
如果最下边提示的是系统源码,那么往上找到第一个自己代码报错处,错误就在这个地方

函数基础二 -- 命名空间,作用域,闭包

 

作用域链:

函数基础二 -- 命名空间,作用域,闭包