名称空间与作用域

名称空间与作用域

什么是名称空间?

存放名字的空间

如果你想访问一个变量值,必须先访问对应的名称空间,拿到名字和对应的地址的绑定关系

名称空间的分类

内置名称空间:

伴随python解释器的启动/关闭而产生/回收,因而是第一个被加载的名称空间,用来存放一些内置的名字

print(print)
#输出结果为
<built-in function print>   #built-in内建
全局名称空间:

伴随python文件的开始执行/执行完毕而产生/回收,是第二个被加载的名称空间,文件执行过程中产生的名字都会存放于该名称空间中

x = 1
def foo(x):
    if x ==1:
        print('苏喂苏喂')
    else:
        print('啦啦啦')


foo(2)
#输出结果为
啦啦啦
局部名称空间
def foo(x):
    y=3 #调用函数时,才会执行函数代码,名字x和y都存放于该函数的局部名称空间中

PS:名称空间的加载顺序是:内置名称空间->全局名称空间->局部名称空间,而查找一个名字,必须从三个名称空间之一找到,查找顺序为:局部名称空间->全局名称空间->内置名称空间。

生命周期

内置名称空间

在python解释器启动时失效,关闭时失效

全局名称空间

当你启动当前py文件时失效,当前页面代码执行结束之后失效

局部名称空间

当你调用当前函数生效,函数体代码执行结束失效

作用域

全局作用域

全局作用域:位于全局名称空间 内置名称空间中的名字属于全局范围,该范围内的名字全局存活(除非被删除,否则在整个文件执行过程中存活) 全局有效(在任意位置都可以使用)

局部作用域

局部作用域:位于局部名称空间中的名字属于局部范围。该范围内的名字临时存活(即在函数调用时临时生成,函数调用结束后就释放) 局部有效(只能在函数内使用)

作用域于名字查找的优先级

在局部作用域查找名字时,起始位置是局部作用域,所以先查找局部名称空间,没有找到,再去全局作用域查找:先查找全局名称空间,没有找到,再查找内置名称空间,最后都没有找到就会返回异常

x = 100           #全局作用域
def foo():
    x = 300       #局部作用域
    print(x)      #在局部找x
    

foo()
#结果为
300                #先在局部作用域查找名字x,找到后直接返回,不再去找下一个

在全局作用域查找名字时,起始位置便是全局作用域,所以先查找全局名称空间,没有找到,再查找内置名称空间,最后都没有找到就会抛出异常

x = 100
def foo():
    x = 300     #在函数调用时产生局部作用域的名字x,只在局部生效,不影响全局


foo()
print(x)       #在全局找x,结果100 

PS: 可以调用内建函数locals()和globals()来分别查看局部作用域和全局作用域的名字,查看的结果都是字典格式。在全局作用域查看到的locals()的结果等于globals()

函数的嵌套

Python支持函数的嵌套定义,在内嵌的函数内查找名字时,会优先查找自己局部作用域的名字,然后由内而外一层层查找外部嵌套函数定义的作用域,没有找到,则查找全局作用域

x = 1
def outer():
    x = 2
    def inner():
        x = 3
        print('inner x:%s' %x)


    inner()
    print('outer x:%s' %x)

outer()
#结果为
inner x:3
outer x:2

在函数内,无论嵌套多少层,都可以查看到全局作用域的名字,若要在函数内修改全局名称空间中名字的值,当值为不可变类型时,则需要用到global关键字

x = 1
def foo():
    global x  #声明x为全局名称空间的名字
    x = 2


foo()
print(x)
#结果为
2

当实参的值为可变类型时,函数体内对该值的修改将直接反应到原值

num_list = [1, 2, 3]
def foo(num):
    num.append(5)


foo(num_list)
print(num_list)
#结果为
[1, 2, 3, 5]

对于嵌套多层的函数,使用nonlocal关键字可以将名字声明为来自外部嵌套函数定义的作用域(非全局)

def f1():
    x = 2
    def f2():
        nonlocal x
        x = 3
    f2()
    print(x)
f1()
#结果为
3

函数对象

函数可以被引用
def sum(x, y):
    z = x + y
    print(z)
func = sum
print(func(1,2))
#结果为
3
None

函数可以作为容器类型的元素

函数可以作为参数传入另外一个函数
函数的返回值可以是一个函数

1.函数对象
- 是什么?
函数的名字就是函数对象,函数名指向的是函数的内存地址。

    - 有什么用?
        - 可以被引用
        - 可以被当做参数传入
        - 可以被当做函数的返回值
        - 可以当做参数传入容器中
            {"key": func--X0...}

    - 函数对象的应用:
        补充--》可以优雅地取代if分支

2.函数嵌套
    - 函数嵌套定义: 让内层函数封闭起来,不让外部直接调用。
        def func1():

            def func2():
                pass

            return func2

        func2()



    - 函数嵌套调用: 将复杂并且小的功能,在函数内部调用,解决代码结构清晰问题。
        def login():
            pass

        def register():
            pass

        # 使用func函数的前提是,必须先注册,登录,再使用
        def func():
            register()
            login()
            func的逻辑代码
            ...

3.名称空间与作用域
    - 名称空间什么是?
        用来存放名字的,名称空间是一个在内存中的空间。
        x = 100
        def func():
            pass
        - 内置名称空间:
            在python解释器启动时产生,关闭时销毁。

        - 全局名称空间:
            执行当前的py文件时产生,文件执行结束后销毁,关闭解释器时彻底销毁。

        - 局部名称空间:
            在执行函数时产生,临时存活,函数调用结束时销毁。

        - 名称空间 加载顺序与查找顺序:
            - 加载顺序:内置 ---> 全局 ---> 局部
            - 查找顺序: 局部 ---> 全局 ---> 内置

    - 作用域: 名称空间作用的范围
        - 全局:
            内置名称空间 + 全局名称空间
            - 只要程序一直执行,永久存活,若程序结束,则销毁

        - 局部:
            局部的名称空间 + 局部的局部的名称空间
            - 只要程序一直执行,调用函数时存活,结束时销毁

今日内容

原文地址:https://www.cnblogs.com/a736659557/p/11892354.html