名称空间与作用域

1 名称空间(namespaces):

名称空间是存放各种名字的地方,是对栈区的一种划分

名称空间可以分为三种:

内置名称空间,全局名称空间,局部名称空间

有了名称空间之后,就可以在栈区中存放相同的名字, 而不会互相干扰

1.1 内置名称空间

内置名称空间存放的名字:python解释器内置的名字

内置名称空间的存活周期:python解释器启动则产生,python解释器关闭则销毁

>>> print
<built-in function print>
>>> input
<built-in function input>

1.2 全局名称空间

全局名称空间存放的名字:只要不是局部定义、也不是内置的,剩下的都是全局名称空间的名字
全局名称空间的存活周期:python文件执行则产生,python文件运行完毕后销毁

x=10
if 13 > 3:
    y=20
    if 3 == 3:
        z=30

# func=函数的内存地址
def func():
    a=111
    b=222

class foo:
    pass
# 其中x,y,z,func,foo都存放于全局名称空间

1.3 局部名称空间

局部名称空间存放的名字:在调用函数时,运行函数体代码过程中产生的函数内的名字
局部名称空间的存活周期:在调用函数时存活,函数调用完毕后则销毁

def func(a,b):
    pass

func(10,1)
func(11,12)
func(13,14)
func(15,16)
# 上面共产生了四次局部名称空间,也销毁了四次局部名称空间

1.4 名称空间的加载顺序

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

1.5 名称空间的销毁顺序

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

1.6 名字的查找优先级:从当前所在的位置向上一层一层查找

如果当前在局部名称空间:

先从局部名称空间查找,

如果不存在,再从全局名称空间寻找,

如果不存在,再从内置名称空间寻找

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

如果当前在全局名称空间:

先从全局名称空间寻找,

如果不存在,再从内置名称空间寻找

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

注意点:

  1. 函数定义时会确定函数内名字的值所在的名字空间

    (原因: 定义时需要检查语法)

  2. 定义时只确定使用哪个名称空间的值,而不确定这个名字的值

    (原因: 定义时只检查语法,不需要数值)

下面为示例 :

input=333
def func():
    input=444
    print(input)  # input局部空间内有,使用局部空间的input

func()
# 查看局部空间的input是否定义了值----->444
# 444 

input=333
def func():
    print(input) # input局部空间内没有,全局空间内有,使用全局空间的input

func()
# 查看全局空间的input是否定义了值----->333
# 333 
def func():
    print(input)# input局部空间内没有,全局空间内也没有,内置空间有,使用内置空间的input

func()
# 查看内置空间的input是否定义了值-----><built-in function input>
# <built-in function input>
input=333
def func():
    input=444
func()
print(input)# input全局空间内没有,内置空间有,使用内置空间的input
# 查看内置空间的input是否定义了值-----><built-in function input>
# 333
def func():
    print(x)# x局部空间内没有,全局空间内有,使用全局空间的x
x=111

func()
# 查看内置空间的input是否定义了值-----><built-in function input>
# 111
# 注意:不会报错,若x=111在func()代码执行后,会报错,因为没定义x的值
# 名称空间的"嵌套"关系是以函数定义阶段为准,与调用位置无关
x=1
def func():
   print(x)	# x局部空间内没有,全局空间内有,使用全局空间的x


def foo():
    x=222
    func()

foo()
# 1在执行前定义了,不报错
# 结果: 1
input=111
def f1():
    def f2():
        print(input)# input局部空间f2()内没有,局部空间f1()内有,使用局部f1空间的input
    input=222
    f2()

f1()
# 222在执行前定义了,不报错
# 222
input=111
def f1():
    def f2():
        input=333
        print(input)# input局部空间f2内有,使用局部f2空间的input
    input=222
    f2()

f1()
# 333在执行前定义了,不报错
# 333
input=111
def f1():
    def f2():
        print(input)# input局部空间f2()内没有,局部空间f1()内没有,全局空间内有,使用全局空间的input
    f2()

f1()
# 111在执行前定义了,不报错
# 111
x=111
def func():
    print(x) # x局部空间内有,使用局部空间的x
    x=222

func()
# 使用局部空间的x输出,但是x还没定义,不能输出,报错
# UnboundLocalError: local variable 'x' referenced before assignment

2 作用域

作用域也就是作用范围,作用域可以分为两类: 全局作用域 和 局部作用域

2.1 全局作用域:

全局作用域包含内置名称空间与全局名称空间

特点:

1、全局存活
2、全局有效:被所有函数共享

x=111
def foo():
    print(x,id(x))

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

foo()
# 111 140726763447392

bar()
# 111 140726763447392

print(x,id(x))
# 111 140726763447392

2.2 局部作用域

局部作用域包含局部名称空间的名字
特点:

1、临时存活
2、局部有效:函数内有效

def foo(x):
    def f1():
        def f2():
            print(x)
        f2()
    f1()

foo(1)
# 1
# LEGB
# local			本地,最内层
# enclosing		外层嵌套
# global		全局
# builtin		内置


# global
def f1():
    # enclosing
    def f2():
        # enclosing
        def f3():
            # local
            pass

3 申明所在名称空间

如果我们想在局部修改外部的变量,

可以使用global或nonlocal方法申明变量所属的名称空间,

之后对这个名字的操作就不再是对本地local的名字进行操作,而是对申明的名字操作

x=111
def func():
    x=222

func()
print(x)
# 111

3.1 global

global: 申明后,可以修改全局名称空间中包含的名字对应的值(不可变类型)

x=111
def func():
    global x # 声明x这个名字是全局的名字,不要再造新的名字了
    x=222

func()
print(x)
# 222
# 对于可变数据类型,没有必要申明global,不申明依旧可以修改全局名称空间中的l
l=[111,222]
def func():
    l.append(333)

func()
print(l)

3.2 nonlocal

nonlocal: 申明后,可以修改函数外层函数包含的名字对应的值(不可变类型)

x=0
def f1():
    x=11
    def f2():
        nonlocal x
        x=22
    f2()
    print('f1内的x:',x)

f1()
# f1内的x: 22
# 对于可变数据类型,没有必要申明nonlocal,不申明依旧可以修改函数外层函数中的列表
def f1():
    x=[]
    def f2():
        x.append(1111)
    f2()
    print('f1内的x:',x)

f1()
# f1内的x: [1111]
 posted on 2020-03-19 21:20  wwwpy  阅读(128)  评论(0编辑  收藏  举报