命名空间、作用域、取值顺序:

全局命名空间 、局部命令空间、内置命令空间的关系
当python解释器,对一个文件从上到下开始执行代码时,在内存中就为文件开个内存空间,在遇到变量 和 函数的定义时,就将 “变量名和值的关系”
及 “函数名和值的关系”保存在这个内存空间中,这块内存空间---叫做全局命令空间 或者叫做 全局名称空间。当整个py文件执行结束,全局名称空间从内存中释放。
全局命令空间中,保存在文件中,函数外的变量的名字 和 变量内容对应的内存地址,及 函数名和函数体对应的内存地的映射关系,可以叫做字典。

python解释器,对py文件,从上向下执行代码时,当遇到函数的调用或叫函数的执行时,会在内存中临时开辟一个内存空间,用来保存函数体内部定义的变量,及子函数映射关系。
当函数执行完毕,临时空间释放,这个临时空间, 我们称之为局部命令空间或局部名称空间。

内置命令空间;当py文件运行前,python解释器,加载到内存中,创建一个内存空间,用来存放内置函数input,print,len 及 类 list,tuple ,dict,str等的映射关系,这个内存
空间,我们称之为内置名称空间。内置命令空间的东本,全局命令空间,可以引用,调用,局部命令空间,也可以调用。同样,当解释器执行完py文件时,也退出,释放出该块内存空间。

在不同的空间的取值顺序
在全局空间,即py文件的任意位置,除掉函数内部,引用对象,先在全局空间找,再到内置空间找,找不到就报错。 全局空间找 ----> 内置命令空间找
在局部空间,即函数内部的任意位置,引用对象,先在局部命名空间找,再到全局命令空间找,最后到内置空间找,找不到则报错。 局部空间找 ---> 全局名称空间找 ---> 内置命名空间找

作用域:

按照对象的作用范围,或者叫生命周期,分为全局作用域 ,局部作用域 。
全局作用域:对于内置名称空间,全局名称空间的对象 ,在整个文件执行过程中一直有效,直到文件执行结束,才结束其生命周期。因此我们说,内置空间、全局空间的对象它的作用范围,或者
作用域 ,为全局作用域。
局部作用域 :对于函数而言,当执行时,开辟了局部命名空间,局部命令空间的对象,仅在函数执行过程中,一直有效,函数执行结束 ,其生命周期结束。因此我们说,局部命名空间的对象它的作用
范围或者叫作用域,为局部作用域。 

def len(obj):
    print(20)
    return 20
ret = len('hello world')  # 我们知道python有一个内置函数len(),它是内置空间的,但是我们在全局命令空间调用len时,先到全局空间找,找到,后面有一个括号 ,就执行全局空间定义的len()函数
print(ret)                            # 相当于去内置空间len()函数进行了覆盖


def func8(obj):
    len(obj)                            # 在局部空间时,执行代码时,先在局部空间找函数名,没有找到,再到全局名称空间,找到执行
func8([1,3,5])           # 控制台打印 20


def func9():
    def len():
        print("局部命名空间")
    len()                                    # 当执行func9()函数时,先定义局部空间中的len(),然后调用执行len(),先在局部空间去找,找到就执行

func9()    # 控制台中打印输出 : 局部命名空间
  
print(len("str"))   # 3    在全局空间没有找到len,再到内置命名空间

def func1(obj):
   return  len(obj)          # 函数执行时,先到局部命名内间找,没有找到再到全局命名空间找,没有找到,最后到内置名称空间找。
print(func1("sbcde"))  # 5 

 

 

在函数中, global  和  nonlocal 关键字的详解:

# nonlocal 关键字 ,只能用在子函数中,声明引用 上级的变量(直接上级没有,就到上上级,直到最顶端上级函数没有,就报错,先找到先引用
# nonlocal ---子函数对父函数中的变量的修改,直接父级没有,到上上父级到,不包括全局作用命令空间
def GrandFather():
        count = 6
        def Father():
            count = 12            # 被下级函数,声明nonlocal count的引用
            def son():
                nonlocal count   # 子函数中,用nonlocal声明一个变量,它会从它的上级函数去找,找到就引用
                count = count + 1
                print(count)
            son()
        Father()
# 函数调用
GrandFather()    # 输出结果,打印13


def GrandFather():
    count = 6                     # 被下级的 nonlocal count 找到,被引用

    def Father():
        # count = 12  # 现在我这一行代码,注释掉了

        def son():
            nonlocal count  # 子函数中,用nonlocal声明一个变量,它会从它的上级函数去找,直接上级没有,就到上上级,找到就引用
            count = count + 1
            print(count)
        son()
    Father()

# 函数调用
GrandFather()


#$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$####################
# count = 10
# def GrandFather():
#     # count = 6           # 这一行也注释掉
#
#     def Father():
#         # count = 12  # 被下级函数,声明nonlocal count的引用
#
#         def son():
#             nonlocal count  # 子函数中,用nonlocal声明一个变量,它会从它的上级函数去找,找到就引用,但是不引用全局命令空间,
#                             # 在所有上级,上上级....函数中都找不到,则报错:SyntaxError: no binding for nonlocal 'count' found
#             count = count + 1
#             print(count)
#         son()
#     Father()
#
# GrandFather()

# 子函数中的 nonlocal variable 引用自哪一层,那层及以下层全部发生改变

# global关键字 用在函数中,用于声明一个变量是全局命名空间的变量,如果在全局空间,没有找到,则创建,否则直接引用

# 第一种情况:函数中通过 global variable 声明的全局变量,在全局命令空间已经定义,直接引用
globalv = "I am a global variable"
def func():
    global globalv
    print(globalv)
func()    # 输出,打印: I am a global variable


# 第二种情况:函数中通过 global variable 声明的变量,在全局命名空间没见有定义,那么在执行函数体过程中,会在全局名称空间
# 创建此变量,并用作用域,为全局作用域,即生命周期为整个文件
# def func2():
#     global global_test
#     global_test = "I am from function"
#     print(global_test)
# func2()     # 屏幕打印:I am from function
# print(global_test) # I am from function


# 第三种情况:在函数中,声明了global variable ,但未调用过此函数,那么,这时在全局空间引用此变量,会报错
def func2():
    global global_test
    global_test = "I am from function"
    print(global_test)
# func2()     # 把这一行代码注释掉,即虽然定义了函数,但是不调用,没有调用 ,就不会执行global global_test 语句,就不会在全局命令空间,创建变量
print(global_test) # 所以,在全局命名空间,调用变量时,报错: NameError: name 'global_test' is not defined  名称错误

 对于global 和 nonlocal 关键字补充:

# 7题:
# 7.1
# a = 2
# def wrapper():
#     print(a)
# wrapper()
# 答:在局部空间,可以引用 全局命名空间的对象,所以此代码成立。

# # 7.2
# a = 2
# def wrapper():
#     a += 1
# print(a)
# wrapper()

# 答: 此代码不成立,在局部名称空间,不能修改全局变量,需要声明为使用全局变量
# 解决办法:
# def wrapper():
#     global a
#     a += 1
# print(a)
# wrapper()
# print(a)

# 7.3 题:
def wrapper():
    a = 1
    def inner():
        print(a)
    inner()
wrapper()

# 答 : 可以上级函数的命令空间的变量对下级函数而言,是可见的,可以直接引用
# 7.4 题:
def wrapper():
    a = 1
    def inner():
        a += 1
        print(a)
    inner()
wrapper()
# 答 :代码不成立,下级函数引用上级函数里的变量,并修改,不成立,要修改的话,用nonlocal关键字声明。

最后总结: 在函数里可以直接引用 全局名称空间的 变量,但要在函数里--修改--全局名称空间的变量,则在函数里用global关键字声明 变量;
下级函数,可以直接引用上级函数里的变量,但下级函数要对上级函数(包括上上级....)的变量修改,则在函数内要用nonlocal关键字声明该变量

 globals() 和 locals()函数:

#globals() 与 locals()函数:
# glocals()函数 :返回执行这条命令的,当前作用域的全局变量的一个字典
# locals() : 返回执行这条命令时,当前作用域的局部变量的一个字典

# 当在文件中,函数外执行 时, 当前作用域 就是全局变量 所处的 全局命名空间,因此 globals() 与 locals() 结果 一样
print(globals())
print(locals())
def test():
    a = 2
    b = 3
    print(globals())
    print(locals())    #  {'b': 3, 'a': 2}
test()

def test1():
    a = 2
    b = 3
    def inner():
        c = 5
        d = 6
        print(globals())  # 全局的不变
        print(locals())  #  {'d': 6, 'c': 5}
    inner()
test1()

函数名可以作为容器类数据类型的元素,常用应用场景:

def register():
print("正在注册")
pass
def login():
print("正在登陆")
pass
def purchase():
print("购买功能正在开发中.....")
pass
def escape():
print("你已成功逃逸.....")
exit()
pass

function_dic = {1:register,2:login,3:purchase,4:escape}
while 1:

choice_num = input('''
1 .................. 注册
2 .................. 登陆
3 .................. 购买
4 .................. 退出
请输入【1-4】:
''')
if choice_num.isnumeric():
if int(choice_num) in list(range(1,5)):
function_dic[int(choice_num)]()



posted on 2018-08-16 14:00  yellwonfin  阅读(183)  评论(0编辑  收藏  举报