Python的命名空间namepaces

1、名称空间(namepaces)与作用域。
  名称空间即存放名字与对象映射/绑定关系的地方。对于x=3,Python会申请内存空间存放对象3,然后将名字x与3的绑定关系存放于名称空间中。
  
  del x表示清除该绑定关系
  
  名称空间:是一个非常重要的思想,不是真正的空间,只是虚拟出来的一块空间,
  作用是:在不同的空间内存放相同是名字,例如:一班有个同学叫张三,男。二班也有同学叫张三,女。
  命名空间分为三类:
    (1)内置名称空间
    (2)全局名称空间
    (3)局部名称空间

     (1)三种名称空间用途与存活周期(这里的活动周期是指python运行程序的三个阶段:启动python解释器,加载文件内容到内存,python执行程序)

 一、名称空间namespace:用于存放名字的地方,是对栈区的划分。
    有了名称空间之后,就可以在栈区中存放相同的名字,
    详细的名称空间分为三种:
    1、内置名称空间:有一个
        存放的名字:存放的是python解释器内置的名字,
        举例如下:
        >>> print
        <built-in function print>
        >>> input
        <built-in function input>
        存活周期:关于python运行程序的三个阶段
            开始:python解释器启动。
            结束:python解释器关闭。
    2、全局名称空间:有一个
        存放的名字:运行顶级代码所产生的名字,只要不是函数内定义的和内置的,全为全局名称空间。
            顶级:在python解释器里:没有缩进的叫顶级
            例如:
            示例一:import os
            示例二: x = 10
            示例三:这里的y和z都是全局命名空间
                if 13 > 3:
                    y = 20
                    if 3 == 3:
                        z=30
            示例四:func=函数的内存地址,是全局命名空间,a和b数据局部命名空间
                def func():
                    a=111
                    b=222
        存活周期:
            开始:python文件执行则开始。
            结束:python文件运行完毕后结束。
    3、局部名称空间,可以有多个
        存放的名字:在调用函数时,运行函数体代码过程中产生的函数内的名字。
        示例:func=函数的内存地址,是全局命名空间,a和b数据局部命名空间
            def func():
                a=111
                b=222
        存活周期:
            开始:在调用函数时存活。
            结束:在函数调用完毕后则销毁。

  (2)三种名称空间的加载顺序
三种名称空间的加载顺序:
    内置名称空间》全局名称空间》局部名称空间
    在运行python解释器时:内置名称空间和全局名称空间一定存在。局部名称空间可以在调用函数时在创建。
三种名称空间的销毁顺序:
    局部名称空间》全局名称空间》内置名称空间
    (3)三种名称空间的查找名字的优先级
三种名称空间的查找优先级:从当前所在位置开始,逐层向上一级查找,
内置名称空间
全局名称空间
局部名称空间
局部名称空间没有去全局名称空空间,全局名称空间没有再去内置名称空间。
查找局部的
input = 333  # 全局的
def func():
    input = 444  # 局部的
    print(input)

func()  # 444

查找全局的
input = 333  # 全局的
def func():
    # input = 444  # 局部的
    print(input)

func()  # 333

查找内置的
# input = 333  # 全局的
def func():
    # input = 444  # 局部的
    print(input)

func()  # <built-in function input> # 内置的
从当前所在位置开始,逐层向上一级查找
# 示范1:名称空间实例:查找顺序
# x = 111
# def func():
#     print(x)  # 111
#     print(y)  # 222
# y = 222
# func()  # 111

# 示范2:名称空间的“嵌套”关系,是以定义阶段为准,与调用位置无关
x = 1
def func():  # 此处为局部的
    print(x)  # 嵌套的为全局的x=1

def foo(): # 此处为局部的
    x = 222  # 在此处定义个x =222
    func()

foo()  # 结果为1 重点:名称空间的“嵌套”关系,是以定义阶段为准,与调用位置无关
# 实例3:函数的嵌套定义,从当前位置向上一层进行查找。
input = 111  # 当此处被注释打印<built-in function input>
def f1():
    input = 222  # 当此处被注释打印111
    def f2():
        input = 333  # 当此处被注释打印222
        print(input)
    f2()
f1()  # 输出结果:333

如下图所示:
# 实例4:查找顺序以定义阶段为准
x = 111
def func():
    print(x) # 此处的x为局部的,当语法扫描到此处时候,该处的x未定义
    x = 222  # 当此处定义了x=222时此处出现的语法逻辑上错误,针对变量需要先定义后使用

func()  #报错: UnboundLocalError: local variable 'x' referenced before assignment
# 实例5:
x = 111
def func():
    x = 222  # 为避免实例4的错误,应在此处定义x
    print(x)
    # x = 222

func()
3、作用域:作用范围,对名称空间归类,有两大类(全局和局部)
(1)全局作用域:内置名称空间、全局名称空间
       1、全局存活:除非被删除否则在文件执行过程中存活
 2、全局有效:被所有函数共享,在任意位置都可以使用。
# 不同函数内的名字独立
def foo():
x = 111
print(x,id(x))

def bar():
x = 222
print(x,id(x))

foo() # 111 140715383776352
bar() # 222 140715383779904
# 全局存活,全局有效
x = 111
def foo():
print(x,id(x))

def bar():
print(x,id(x))
foo() # 111 140715385939040
bar() # 111 140715385939040
    (2)局部作用域 :局部名称空间的名字
     1、临时存活:函数在调用时临时生成,函数在调用结束后释放
     2、局部有效:只能在函数内使用它
def func(x):
    def f1():
        def f2():
            print(x)

  LEGB:

# 名称空间分为四个:LEGB为便于记忆 L;local,E:enclosing, G:global,B:built-in
# 局部名称空间分为两类:
# B
# G
def f1():
    # E
    def f2():
        # E:enclosing
        def f3():
            # L:local
            print()
     global
# 实例1:修改全局变量
# x = 111
# def func():
#     # global x  # 修改全局变量
#     x = 222
#     print(x)
#
# func()  # 222
# print(x)  # 111

# 实例2:如果想要在局部修改全局的名字的对应的值(这里针对不可变类型,必须使用global),需要使用global修改全局变量
# x = 111
# def func():
#     global x  # 声明x这个名字时全局的名字,不在早遭新的名字了
#     x = 222
#     print(x)
#
# func()  # 222
# print(x)  # 222

# 实例3:针对可变类型
# l = [111,222]
# def func():
#     l = 333
#     print(l)
#
# func()  # 333
# print(l)  # [111, 222]
l=[1,2,3]
def func():
global l # 针对不可变类型,有global和无global的效果是一样的
l.append(4)

func()
print(l) # [1, 2, 3, 4]
# 体验一下有无调用的效果
# def func():
#     global x
#     x = 111
# print(x)  # NameError: name 'x' is not defined

def func():
    global x
    x = 111
func()
print(x)  # 111
nonlocal作用
# nonlocal(了解):实例1:修改函数外层函数包含的名字对应的值(不可变类型)
# x = 0
# def f1():
#     x = 11
#     def f2():
#         global x  # 修改全局变量也就是说把x=0的值改成了22
#         x = 22
#     f2()
#     print("全局的x变化后查看f1内的x:",x)   # f1内的x: 11,发现此处的函数没有变化,如果我想改变它,该如何办?使用nonlocal
# f1()
# print(x)  # 22

# nonlocal(了解):实例2
# x = 0
# def f1():
#     x = 11
#     def f2():
#         nonlocal x  # 从当前层的外一层开始找,没有就报错,SyntaxError: no binding for nonlocal 'x' found
#         x = 22
#     f2()
#     print("全局的x变化后查看f1内的x:",x)   # f1内的x: 22
# f1()
# print(x)  # 0

# nonlocal(了解):实例3
x = 0
def f1():
    x = []  # 此处如果时可变类型,不用声明了,可以直接修改
    def f2():
        x.append(3333)
    f2()
    print("全局的x变化后查看f1内的x:",x)   # f1内的x: [3333]
f1()
print(x)  # 0
针对名称空间的练习操作:
# 作业要求:下述所有代码画图以及分析代码执行流程
# 1、以定义阶段为准,先画出名称空间的嵌套关系图
# 2、然后找到调用函数的位置,写出函数调用时代码的执行过程,涉及到名字的查找时,参照1中画好
#    的嵌套图,标明查找顺序,一层一层直到找到位置7

# # ===================题目一===================
input=333
def func():
    input=444
    print(input)
func()
print(input)

 

# # ===================题目二===================
# def func():
#     print(x)
# x=111
#
# func()
从局部开始找x,局部没有去全局找,找到了x=111
# # ===================题目三===================
# x=1
# def func():
#    print(x)
#
#
# def foo():
#     x=222
#     func()
# x = 333
# foo()  # 333

 # # ===================题目四===================

input=111  # 第四次注释
def f1():
def f2():
# input=444 # 第一次注释
print(input)
# input=222 # 第二次注释

f2()
# input = 333 # 第三次注释
f1()
# 不注释得到的结果:444
# 第一次注释得到的结果:222
# 第二次注释得到的结果:333
# 第三次注释得到的结果:111
# 第四次注释得到的结果:<built-in function input>

 


 # # ===================题目五===================

# x=111
# def func():
#     print(x) #
#     x=222
#
# func()
#
#
# # ===================题目六===================
# x=111
#
# def foo():
#     print(x,)
#
# def bar():
#     print(x)
#
# foo()
# bar()
#
# # ===================题目七===================
# x=1
# def func2():
#     func1()
#
# x=2
# def func1():
#     print(x)
#
# x=3
#
# func2()
#
# # ===================题目八===================
# 1、如下全局变量记录了当前登录用户,编写登录功能,一旦用户登录成功,则将全局变量赋值为当前登录的用户名
# login_user=None
# 2、针对之前编写的查询余额的功能,添加额外的逻辑:如果用户没有登录,则先执行登录功能

# 验证使用locals()和globals()函数的作用,查看名称空间
x = 1
def foo():
    x = 2
    print("局部名称空间:",x)
    # 查看局部名臣空间,结果以字典形式展现
    print(locals())  # {'x': 2}
foo()
print("全局名称空间:",x)
# 查看全局名称空间,结果以字典形式展示
print(globals())
# {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000020CA8200970>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'D:/pycharm/oldboy_29/day015/test015/test015_10global和local.py', '__cached__': None, 'x': 1, 'foo': <function foo at 0x0000020CA83495E0>}
 
原文地址:https://www.cnblogs.com/liunaixu/p/12593217.html