函数的命名空间和作用域

时间:2022-12-11 22:48:31

一、函数的命名空间

命名空间:name space是从名称(name)到对象(object)上的映射。

当一个name映射到一个object上时,这个name和这个object就有了绑定(bind)关系,或者说这个name指向了这个object。

每个name只对应一个object,而一个object可有多个名字。这就是类与实例的关系。

不同的命名空间在不同的时刻被创建,并且有不同的生命周期。

内置的命名空间在python解释器启动的时候创建的,并且一直保留,不会删除。

在python程序中的任何地方,都存在着命名空间。

python中有三种命名空间:

局部命名空间:函数内的名称空间就是局部的。

全局命名空间:写在函数外面的变量名。模块内的命名空间就是全局的。

内置命名空间:python解释器启动时创建的,包括异常内型、内建函数和特殊方法,可以在代码中的任何地方调用。

函数外面的变量可以在函数里面调用,函数里面的变量不能在外边用,因为有独自的作用域。

 

名称空间的加载顺序:

a.python解释器首先运行起来,加载所有内置命名空间中的名字。

b.然后按照顺序加载全局命名空间

c.局部命名空间随函数的调用而创建,随着函数的结束而消除。

 

命名空间的查找顺序:

a.如果在函数内调用一个变量,先在函数内(局部命名空间)查找,如果没有找到则去函数外部(全局命名空间)查找,如果还是没有找到,则去内置命名空间中查找,内置空间再找不到那就只有报错。

b.如果在函数外调用一个一个变量,先查全局命名空间,也就是本地,如果没有找到,那就去内置命名空间中查找,这里找不着也没辙。

 

二、函数的作用域

作用域:一个名字可以使用的区域范围。

全局作用域:内置名字空间和全局名字空间中的名字都属于全局作用域
局部作用域:局部名字空间中的名字属于局部作用域。
局部作用域可以使用全局作用域中的变量
而全局作用域不能使用局部作用域中的变量
局部作用域中的变量又可以被更小的作用域所调用
作用域链:小范围作用域可以使用大范围的变量,但作用域链是单向的,不能反向。

globals():保存了在全局域中的名字和值,无论在哪打印值都一样
locals():保存了当前作用域中变量,根据执行的位置来决定作用域中的内容
如果在全局执行,globals()和locals()的结果是相同的

global :声明参数是全局变量

nonlocal :调用最近的这个参数

 

用几个例子来演示:

(1)代码的加载顺序

#代码执行的顺序
def func2():                             #1  读取函数
    print('my name is func2')             #5
    print('多写一行')                             #6   
    if True:                                          #7
        print('又多写了一行')                      #8
    return 'func2的返回值'                        #9

def func():                              #2
    ret = func2()                            #4   调用函数
    print(ret)                                            #10
    n = 20                                                  #11
    print(n)                                                   #12   

func()                                     #3  执行函数

 

(2)函数的镶嵌

def func():
    def kebi():
        print('我是科比.布莱恩特')
    kebi()    #要想调用kebi,必须先要再func()里面调用

func()

 

(3)作用域

n = 1
def func():
    print(n)      #会报错,在圈子里不能改变圈子外的值
    n = n+1

func()
n = 1
def func():
    global n    #用global来声明这是一个全局变量
    n = n+1
    print(n)

func()

结果:
2

如果想调用局部中的变量

n = 0
def func1():
    n = 1
    def func2():
        nonlocal n  #调用就近的一个局部变量,不会调用全局变量
        n +=1
    func2()
    print(n)
func1()
print(n)

结果:
2
0

 

三、函数的名字

函数名可以赋值

def foo(sr):
    print(sr*2)
bar = foo
bar(123)

结果:
246

 

可以作为一个数据结构的元素

def foo(sr):
    print(sr*2)
lst = [1,2,foo,5]
print(lst)

结果:
[1, 2, <function foo at 0x000002DD65CE4048>, 5]

 <function foo at 0x000002DD65CE4048> foo的内存地址

 

函数可以作为一个函数的参数

def foo(sr):
    print(sr*2)
def bar(lst):
    return lst
print(bar(foo))

结果:
<function foo at 0x000002AE437C4048>

 


函数的名字可以作为一个函数的返回值

def foo(sr):
    print(sr*2)
def bar():
    return foo
print(bar())

结果:
<function foo at 0x000001DF93844048>