5.2 Python 名称空间与作用域

1. 名称空间

1.1 简介
定义一个变量, num = 1, 解释器会申请内存空间存放值1, 将名字num与1的内存地址的绑定关系存在栈区中.

名称空间: 是放名称与对象绑定关系的地方, 是对栈区的一种虚拟的划分, 为了避免程序中标识名称冲突, 
有了名称空间之后就可以在栈区中存放相同的名字, 每个命名空间是独立的, 允许出现相同的标识符名称.
1.2 分类
名称空间划分三个大类:
* 1. 内置名称(built-in names): 解释器内置的名称, : 内置函数, 关键字...
* 2. 全局名称(global names):  自定义的名称, 导入的模块, 顶级的名称(没有缩进的叫顶级)..
* 3. 局部名称(local names): 函数()内部的定义的标识符.
1.3 生命周期
内置: Python解释器启动产生, 关闭销毁.
全局: py文件运行产生, 结束销毁.
局部: 调用函数产生, 调用结束销毁.

产生顺序: 内置 --> 全局 --> 局部 --> 子局部 --> 子子局部 --> ...
销毁顺序: ... --> 子子局部 --> 子局部 --> 局部 --> 全局 --> 内置
1.4 内置名称
# 内置名称, 内部定义好的名称能够直接使用.
>>> print
<built-in function print>
>>> len
<built-in function len>
>>> print('xx')
xx
>>> len('x')
1
1.5 全局名称
* 类似if, for, with等语句, 不存在自己的作用域, 这些语句中定义的名称时全局名称.
# 自定义名称
num1 = 0
# 定义后全局可以使用
print(num1)


# def 关键字定义的名称, 属于顶级的名称.
def func():
    # 在函数中使用全局名称, 不能做计算后续说明.
    print(num1)


# 调用顶级的名称
func()

# if, for 不存在自己的作用域
if True:
    num3 = 3

print(num3)  # 3

for i in range(5):
    # 以最后一次为准
    num4 = i

# 这里提示num3没有定义忽略即可, 在运行for循环后就会定义, Pycharm没法检测.
print(num4)  # 0

1.6 局部名称
def func():
    print('局部空间')

    # 局部变量
    num1 = 1
    print(num1)  # 1

    if True:
        # 局部变量
        num2 = 2

    print(num2)  # 2

    for i in range(4):
        # 局部变量
        num3 = i

    # 提示没有定义, 忽略即可, 在执行for循环后会定义.
    print(num3)  # 3

    # 局部变量(函数可以嵌套)
    def func4():
        ...

    print(func4)


func()

2. 作用域

作用域: 名称空间的作用范围, 决定了程序中哪些位置可以什么名称.
按照名称空间中名称的作用范围可以将三种名称空间划分为两个区域:
* 1.全局作用域: 全局作用域中的名称在整个文件执行过程中都不会被销毁, 在任意位置都可以使用.
    内置名称空间, 全局名称空间属于全局作用域, 全局存活, 全局有效
* 2.局部作用域: 局部作用域中的名称在函数调用时产生, 调用结束时销毁, 只能在函数内使用.
    局部名称空间属于局部作用域, 临时存活, 局部有效.
* 名称的作用域觉
2.1 名字查找优先级
查找准则: 函数的嵌套关系与名字的查找顺序是在定义阶段就已经确定好的与调用位置无关.
Python在查找"名称", 是按照LEGB规则查找的:
L(Local)     指的是所有函数内部的函数.
E(Enclosing) 指的是最外层函数.
G(Global)    指的是全局变量.
B(Built-in)  指的是Python内置保留的名称.

明确自己当前在哪个名称空间中, 再基于当前位置向外查找, 都没有找到就报错: 该名称没有定义
1. LEGB
len = 1


def func1():
    len = 2

    def func2():
        len = 3
        print(len)  # 在当前的名称空间中拿len

    func2()


func1()

2. EGB
len = 1


def func1():
    len = 2

    def func2():
        print(len)  # 向外层的名称空间中拿len

    func2()


func1()

3. GB
len = 1


def func1():
    def func2():
        print(len)  # 向全局的名称空间中拿len

    func2()


func1()

4. B
def func1():
    def func2():
        print(len)  # 向内置的名称空间中拿len

    func2()


func1()

2.2 注意事项
* 1. 在局部内可以直接使用全部变量, 但是这个变量不能做数学运算, 如果做运算, 会报错: 名称没有定义.
因为该变量会被Python解释器认为是局部变量而非全局变量.
count1 = 10


def index():
    print(count1)


index()

count2 = 10


def index():
    print(count + 1)  # NameError: name 'count' is not defined


index()

* 2. 嵌套函数中, 先使用外层函数中的名称, 在定义同样的名称就会报错.
: UnboundLocalError: local variable 'len' referenced before assignment.
: 局部变量'xxx'在赋值之前引用.
def func1():
    num = 2

    def func2():
        # 调用外层的名称, 正确运行.
        print(num + 1)  # 2

    func2()


func1()

def func1():
    num = 2

    def func2():
        # 想在这个调用外层的len, 报错: ↓
        print(num + 1)
        # 使用外层的名称, 往回就不能在此空间定义同样的名称.
        # UnboundLocalError: local variable 'num' referenced before assignmen
        num = 3

    func2()
    

func1()
2.3 修改可变类型值
在不同的名称空间, 修改不可变类型的值, 互不影响. 
num = 1


def func1():
    # 在定义阶段就确定查找关系
    print(num)  # 1


func1()


def func2():
    # 局部的num作用于func2的空间, 不会影响全局的num.
    num = 2  
    print(num)  # 2
    func1()


func2()

运行工具窗口显示:
1
2
1
2.4 修改不可变类型值
在不同的名称空间, 可以修改可变类型的值, 操作的是同一个对象, 相互影响.
list1 = []


def func1():
    func2()
    list1.append('b')
    print(list1)


def func2():
    list1.append('a')


func1()
print(list1)

运行工具窗口显示:
['a', 'b']
['a', 'b']
2.5 globals()函数
Python内置globals()函数: 查看全局的名称, 在全局名称空间中使用, 结果是一个字典类型.
num = 1
print(globals(), type(globals()))  # {... 'num': 1} <class 'dict'>

# 通过globals()定义全局变量
globals()['num2'] = 2
print(globals())  # {... 'num': 1, 'num2': 2}

# 通过globals()取值全局变量的值
print(globals().get('num'))  # 1
print(globals().get('num2'))  # 2

2.6 locals()函数
Python内置locals()函数: 查看局部的名称, 在对应的局部名称中使用, 结果是一个字典类型.
局部名称空间可以用很多个, 查个空间就在那个空间内使用.
def func1():
    b = 1
    print(locals(), type(locals()))  # {'b': 1} <class 'dict'>

    def func2():
        c = 2
        print(locals())  # {'c': 2}

    func2()

    # 通过locals()定义当层局部变量
    locals()['b2'] = 3
    # 通过locals()获取当层局部变量的值
    print(locals()['b'])  # 1
    print(locals()['b2'])  # 3


func1()

2.7 global关键字
global关键字: 在局部空间中设置声明一个全局变量.
在局部修改全局变量的值:
不可变数据类型需要global声明, 不可变类型的值修改都需要通过赋值操作.
可变类型数据类型则不需要声明, 可变类型的值本身是一个容器, 可以通过方法操作, 清空在插入值都是都可的.
# 修改不可变类型
x = 0


def func1():
    # 在局部空间中设置声明一个全局变量x.
    global x
    # 为全局变量x设置值.
    x = 10


func1()
print(x)  # 10

#  修改不可变类型
list1 = []  # 可变类型


def func1():
    # 通过方法可以直接修改
    list1.append(1)


func1()
print(list1)  # [1]

2.8 nonlocal关键字
nonlocal关键字: 在内层的局部空间中声明一个外层的局部空间的名称, 外层是全局就会报错.
仅不可变类型需要nonlocal声明.
def func1():
    x = 0

    def func2():
        nonlocal x  # 在内部局部空间中设置声明一个外部局部空间的名称.
        x = 10  # 修改x的值.

    func2()
    print(x)  # 10

    space = locals()
    print(space)
    # {'func2': <function func1.<locals>.func2 at 0x000001B7774B0510>, 'x': 10}


func1()

#  修改可变类型
list1 = []


def func1():
    list1.append(1)

    def func2():
        list1.append(2)

    func2()


func1()
print(list1)  # [1, 2]

相关推荐

  1. 5.2 Python 名称空间作用

    2024-06-14 02:58:05       30 阅读
  2. 函数的名称空间作用

    2024-06-14 02:58:05       60 阅读
  3. 名称空间作用

    2024-06-14 02:58:05       61 阅读
  4. Python中的名称空间作用

    2024-06-14 02:58:05       60 阅读
  5. python作用

    2024-06-14 02:58:05       28 阅读
  6. 名称空间函数对象

    2024-06-14 02:58:05       55 阅读
  7. Python教程:深入理解Python中的命名空间作用

    2024-06-14 02:58:05       35 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-06-14 02:58:05       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-06-14 02:58:05       101 阅读
  3. 在Django里面运行非项目文件

    2024-06-14 02:58:05       82 阅读
  4. Python语言-面向对象

    2024-06-14 02:58:05       91 阅读

热门阅读

  1. Kotlin 的锁和多线程同步

    2024-06-14 02:58:05       20 阅读
  2. kotlin get() 与 set()

    2024-06-14 02:58:05       82 阅读
  3. RK3588开发笔记-100M网口自协商成1000M网口

    2024-06-14 02:58:05       42 阅读
  4. RedisConfig配置

    2024-06-14 02:58:05       33 阅读
  5. LaneKeepingEnv(自动驾驶仿真)

    2024-06-14 02:58:05       40 阅读
  6. 什么情况下需要进行身份证实名认证?

    2024-06-14 02:58:05       31 阅读
  7. ChatTTS:全新对话式文本转语音系统全面解析

    2024-06-14 02:58:05       32 阅读
  8. 游戏心理学Day13

    2024-06-14 02:58:05       28 阅读