12. 函数的名称空间与作用域

1. 名称空间

1.1 概念

名称空间是存放变量名与变量值映射关系的地方

1.2 分类

1.2.1 内置名称空间

Python解释器运行而产生的名称空间,如def、if、else、len

Python解释器运行---产生

Python解释器关闭---释放

1.2.2 全局名称空间

在python文件中编写的代码运行产生的名字都会存到全局名称空间(函数体代码之外的)

name = 'LeoMessi'  # 变量名name存入全局名称空间

def login():  # 函数名login存入全局名称空间
    pass

if True:
    a = 111  # 变量名a存入全局名称空间
for i in range(10):  # 变量名i存入全局名称空间    
    pass
while True:
    b = 222  # 变量名b存入全局名称空间

python文件开始运行 产生

python文件运行结束 释放

1.2.3 局部名称空间

函数体代码运行产生的都是局部名称空间

def register():
    name = 'ronaldo'  # name存入局部名称空间

函数体代码开始运行  产生

函数体代码运行结束  释放

1.3 名称空间的查找顺序

在查找名字的时候,一定要先搞清楚当前在哪个空间

1. 如果在局部名称空间

   局部名称空间————>  全局名称空间————>  内置名称空间

2. 如果在全局名称空间

  全局名称空间————>  内置名称空间

  (只能向外层不能向里层)

3.代码执行顺序

# 局部名称空间之间如果不是嵌套关系,那么互不干涉
def f1():
    name = 'LeoMessi'
def f2():
    age = 35
    print(name)  # 报错not defined
f1()
f2()

 2. 作用域

2.1 概念

作用域就是名称空间能够作用的范围,即变量名和变量值可以被访问的范围(变量名定义的位置和可以查找的位置)

2.2 分类

内置作用域  Built-in

Built-in(内置):解释器内置的变量,比如int, str等。
作用范围:所有模块(文件)
Python中没有块级作用域。
块级作用域:代码块中的变量,比如if、while、for后面的代码

程序任意阶段、任意位置均可使用(全局有效)

全局作用域  Global

Global(全局):一般模块文件顶层声明的变量具有全局作用域,从外部来看,模块的全局变量就是一个模块对象的属性,仅限于单个模块文件中。

作用范围:当前模块(文件)

 程序任意阶段、任意位置均可使用(全局有效)

 

局部作用域  Local

 

Local(局部变量):暂时的存在,依赖于创建该局部作用域的函数。

函数存在,则局部变量存在;函数不存在,则局部变量不存在。
作用范围:当前整个函数体范围

一般情况下,只在各自局部名称空间中有效(局部有效)

内嵌作用域  Enclosed

Enclosed(嵌套):一般是在函数中嵌套函数的时候,外层函数的变量作用域。
作用范围:闭包函数

 

 

2.3 作用域举例

内置作用域举例:

内建作用域里面提前加载好的  如os

import os

 

全局作用域举例:

自己在文件中定义的变量  

num = 123

 

局部作用域与内嵌作用域举例:

age = 18
# 局部作用域:定义在函数或者类内部的所有变量 # 内嵌作用域:在函数中嵌套函数的时候,外层函数的变量作用域。 def student(): age = 28 # 这里的age对student函数是局部作用域,对inner函数是内嵌作用域 print(f" student my age is {age}") def inner(): age = 38 # 这里的age为inner函数的局部作用域 print(f"inner my age is {age}") inner() student() print(f"global my age is {age}")

作用域的加载顺序:内置 -- 全局 -- 外层 -- 里层
查找循序 : 里层 -- 外层 -- 全局 -- 内置
 查找顺序遵循一个规则 LEGB 规则
L ---> local 局部的局部    最里层的函数
E ---> enclosed  内嵌,相对里层嵌套函数的外层
G ---> global 全局
B ---> built-in 内建

2.4 作用域声明

 

# 字典是可变数据类型 ,大家对于修改字典的时候都是修改的同一块内容空间地址上面的值

# 【总结】
# 【1】名称空间就是存放变量名和变量值映射关系的地方 内建 全局 局部
# 【2】作用域就是变量名和变量值映射关系存放的范围 内建 全局 局部 内嵌
# 【3】如果局部修改全局不可变数据类型 用 global 提高当前作用域级别
# 如果是内嵌修改局部不可变数据类型 用nonlocal 提高作用域级别
# 内嵌作用域无法修改全局作用域中的不可变数据类型

2.5 局部修改全局不可变数据类型

局部修改全局可变数据类型---不需要任何处理---可变数据类型的内存地址不会改变

不可变数据类型---给一个不可变数据类型重新赋值

局部在一般情况下,不能修改全局不可变类型

a = 666
print(a, id(a))  # 666 2877912118896

def change_num():
    a = 999
    print(a, id(a))  # 999 2877912118960

change_num()
print(a, id(a))  # 666 2877912118896

局部使用关键字 global 修改全局不可变类型

a = 666
print(a, id(a))  # 666 1772611630704

def change_num():
    global a  # 在局部使用关键字改变了全局变量a
    a = 999
    print(a, id(a))  # 999 1772611630768

change_num() 
print(a, id(a))  # 999 1772611630768

局部直接修改全局可变数据类型

a = [666]
print(a, type(a), id(a))  # [666] <class 'list'> 2664527109952

def change_num():
    a.append(999)  # 局部修改全局的可变类型,内存地址不发生变化
    print(a, id(a))  # [666, 999] 2664527109952

change_num()
print(a, id(a))  # [666, 999] 2664527109952

2.6 嵌套函数(里层)修改全局不可变数据类型

里层函数无法直接修改全局不可变类型

a = 666
print(a, id(a))  # 666 2409063970416

def change_num():
    def inner():
        a = 999
        print('里层函数', a, id(a))  # 里层函数 999 2409063970480

    inner()

change_num()
print(a, id(a))  # 666 2409063970416

里层函数可使用关键字 global 修改全局不可变类型(外层无相同变量名)

a = 666
print(a, id(a))  # 666 2892394985072

def change_num():
    def inner():
        global a  # 里层使用global对全局不可变实现了修改
        a = 999
        print('里层函数', a, id(a))  # 里层函数 999 2892394985136

    inner()

change_num()
print(a, id(a))  # 999 2892394985136

里层函数使用关键字 global 修改全局不可变类型(外层有相同变量名)

a = 666
print(a, id(a))  # 666 2465023850096

def change_num():
    a = 111
    print(a, id(a))  # 111 2465022807728

    def inner():
        global a  # global使该函数以下所有的a都成为了全局a
        print('里层函数', a, id(a))  # 里层函数 666 2465023850096
        a = 999
        print('里层函数', a, id(a))  # 里层函数 999 2465023850160

    inner()
change_num()
print(a, id(a)) # 999 2465023850160

里层函数使用 nonlocal 关键字修改外层函数不可变类型

a = 666
print(a, id(a))  # 666 2836141569648

def change_num():
    a = 111
    print(a, id(a))  # 111 2836140527280

    def inner():
        nonlocal a
        print('里层函数', a, id(a))  # nonlocal使得里层函数与外层函数的a保持一致
        # 里层函数 111 2836140527280
        a = 999
        print('里层函数', a, id(a))  # 里层函数 999 2836141569712

    inner()

change_num()
print(a, id(a))  # 666 2836141569648

2.7 global与nonlocal小结

global声明全局变量,加载到的是全局的不可变数据类型

nonlocal声明里层函数的外层函数变量,加载到的是里层函数的外层函数变量

 

posted @ 2024-07-29 23:26  hbutmeng  阅读(3)  评论(0编辑  收藏  举报