函数的名称空间和作用域

命名空间

   一、什么是python的名称空间

  名称到对象的映射。命名空间是一个字典的实现,键为变量名,值是变量对应的值。各个命名空间是独立没有关系的,一个命名空间中不能有重名,但是不同的命名空间可以重名而没有任何影响。

通俗讲:名称空间就是存放名字的地方,三种名称空间,(之前遗留的问题x=1,1存放于内存中,那名字x存放在哪里呢?名称空间正是存放名字x与1绑定关系的地方)
原文链接:https://blog.csdn.net/lmseo5hy/article/details/80353099

 

  二、名称空间的分类

  • 内置名称空间 (Built-in)

   存放着python的内置名称,如内置语言的名称如 len,char 和一些异常的名称 BaseException等,在任何模块都可以被调用,且随着python解释器的启动而产生,关闭而回收,因此它是第一个被加载的名称空间.

>>> len
<built-in function len>
  • 全局名称空间

   模块中定义的名称,记录了模块的变量,包括函数、类、其它导入的模块、模块级的变量和常量,伴随着python文件的执行而产生

  • 局部名称空间

   函数中定义的名称,记录了函数的变量,包括函数的参数和局部定义的变量,只有调用函数时才会产生,调用完成时便会被回收

>>> def func():
...     a = 1
...
>>> a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined
>>>

 

  三、命名空间的加载顺序

         内置命名空间(程序运行前加载)-->全局命名空间(程序运行中:从上到下加载)-->局部命名空间(程序运行中:调用时才加载)

 

  四、命名空间的查找顺序

          局部的命名空间--> 全局命名空间 -> 内置命名空间。

     当这三个命名空间还找不到时,会抛出NameError 异常

 

 

函数的作用域

作用域就是一个 Python 程序可以直接访问命名空间的正文区域。

在一个 python 程序中,直接访问一个变量,会从内到外依次访问所有的作用域直到找到,否则会报未定义的错误。

  一、四种作用域和查找顺序

  • L(Local):最内层,包含局部变量,比如一个函数/方法内部。
  • E(Enclosing):包含了非局部(non-local)也非全局(non-global)的变量。比如两个嵌套函数,一个函数(或类) A 里面又包含了一个函数 B ,那么对于 B 中的名称来说 A 中的作用域就为 nonlocal。
  • G(Global):当前脚本的最外层,比如当前模块的全局变量。
  • B(Built-in): 包含了内建的变量/关键字等。,最后被搜索

  所以查找顺序为 : L –> E –> G –> B

二、全局变量和局部变量   

  • 全局变量 : 定义在函数外的拥有全局作用域,在整个文件执行过程中都存在,任意位置都能调用(创建类的另说)
  • 局部变量 : 只能在其被声明的函数内部访问,而全局变量可以在整个程序范围内访问。调用函数时,所有在函数内声明的变量名称都将被加入到作用
#!/usr/bin/env python
# -*- coding: utf-8 -*-
total = 0  # 这是一个全局变量


def sum(x, y):
    # 返回2个参数的和."
    total = x + y  # total在这里是局部变量.
    print("函数内是局部变量 : ", total)
    return total


sum(1, 2)
print("函数外是全局变量 : ", total)


"""
函数内是局部变量 :  3
函数外是全局变量 :  0
"""
View Code

 

三、global 和 nonlocal 关键字

   当我们想在内部作用域修改外部作用域的变量时,可以使用 global 和 nonlocal 关键字.

  • global 关键字 : 修改全局变量 
#!/usr/bin/env python
# -*- coding: utf-8 -*-
total = 0  # 这是一个全局变量


def sum(x, y):
    # 返回2个参数的和."
    global total
    total = x + y  # total在这里是局部变量.
    print("函数内是局部变量 : ", total)
    return total


sum(1, 2)
print("函数外是全局变量 : ", total)

"""
函数内是局部变量 :  3
函数外是全局变量 :  3
"""
View Code
  • nonlocal关键字 : 修改嵌套作用域(enclosing 作用域,外层非全局作用域),如果嵌套了多层函数,nonlocal 会从当前函数的上一层函数开始一层层查找,知道找到最外层,若没找到,则会抛出异常
def func1():
    # 返回2个参数的和."
    a = 1
    print("start a : ", a)

    def func2():
        b = 2

        def func3():
            nonlocal a
            a = 3

        func3()

    func2()
    print("end a : ", a)

func1()

"""
start a :  1
end a :  3
"""
View Code

 

 四、局部变量引用问题

a = 1
def test():
    a = a + 1
    print(a)


test()

"""
UnboundLocalError: local variable 'a' referenced before assignment
"""

       这是因为在函数内部对变量赋值进行修改后,该变量就会被Python解释器认为是局部变量而非全局变量,当程序执行到a=a+1的时候,因为这条语句是给a赋值,所以a成为了局部变量,那么在执行return        a(或是print a)的时候,因为a这个局部变量还没有定义,自然就会抛出这样的错误。

  解决这个问题可以有以下几种方法:

   1. 在函数内部声明global a

 2.在函数内部重新定义一个a变量

 3.通过函数传递参数

 

posted @ 2019-11-10 13:20  想吃手抓饼  阅读(179)  评论(0编辑  收藏  举报