python:命名空间、变量作用域

一、命名空间:
1、Python使用叫做命名空间的东西来记录变量的轨迹。命名空间是一个字典(dictionary),它的键就是变量名,它的值就是那些变量的值。
2、命名空间可以理解为一个容器。在这个容器中可以装许多标识符。不同容器中的同名的标识符是不会相互冲突的。

二、理解python的命名空间需要掌握三条规则:
第一,赋值(包括显式赋值和隐式赋值:模块导入,函数和类的定义等)产生标识符,赋值的地点决定标识符所处的命名空间。
第二,函数定义、模块、类定义(包括def和lambda)产生新的命名空间。
第三,python搜索一个标识符的顺序是"LEGB"。

所谓的"LEGB"是python中四层命名空间的英文名字首字母的缩写。
1、第一层L(local),表示在一个函数定义中,而且在这个函数里面没有再包含函数的定义。 (局部命名空间)
2、第二层E(enclosing function),表示在一个函数定义中,但这个函数里面还包含有函数的定义,其实L层和E层只是相对的。
3、第三层G(global),是指一个模块的命名空间,也就是说在一个.py文件中定义的标识符,但不在一个函数中。 (全局命名空间)
4、第四层B(builtin),是指python解释器启动时就已经具有的命名空间,之所以叫builtin是因为在python解释器启动时会自动载入__builtin__模块,这个模块中的list、str等内置函数的就处于B层的命名空间中。 (内置命名空间)

例1:

>>> g = int('0x3', 0)
>>> def outFunc():
  e = 2
    g = 10
  def inFunc():
     l = 1
     return g + e
    return inFunc()
>>> outFunc() ===> 12

来详细看看这段代码中的标识符。

第1行,适用第一条规则“赋值产生标识符”,因此产生一个标识符g。“赋值的地点决定标识符所处的命名空间”,因为g是没有在一个函数定义中,因此g处于'G'层命名空间中。这一行中还有一个标识符,那就是int。那么int是在什么地方定义的呢?由于int是内置函数,是在__builtin__模块中定义的,所以int就处于'B'的层命名空间中。

第2行,适用第一条规则,由于def中包含一个隐性的赋值过程,这一行产生一个标识符outFunc,outFunc并不处于一个函数定义的内部,因此,outFunc处于'G'层命名空间中。此外,这一行还适用第二条规则,产生一个新的命名空间。

第3行,适用第一条规则,产生个标识符e,而且由于这是在一个函数定义内,并且内部还有函数定义,因此e处于'E'层命名空间中。

第4行要注意,适用第一条规则,产生一个标识符g,这个g与e一样外于'E'层命名空间中。这个g与第一行的g是不同的,因为所处的命名空间不一样。

第5行,适用第一条规则,产生一个处于'E'层命名空间的标识符inFunc。与第2行一样,这一行定义函数也产生一个新的命名空间。

第6行,适用第一条规则,产生一个标识符l,由于这个l处于一个函数内部,而且在这个函数内部没有其他函数的定义,因此l处于'L'层命名空间中。

第7行,适用第三条规则,python解释器首先看到标识符g,按照LEGB的顺序往上找,先找L层(也就是在inFunc内部),没有。再找E层,有,值为10。因此这里的g的值为10。寻找过程到为止,并不会再往上找到'G'层。寻找e的过程也一样,e的值为2。因此第9行的结果为12。

总结:如果在不同的命名空间中定义了相同的标识符是没有关系的,并不会产生冲突。寻找一个标识符的值过程总是 从当前层开始往上找的
例2:
info = "Adress : "
def func_father(country):
    def func_son(area):
        city= "Shanghai " #此处的city变量,覆盖了父函数的city变量
        print(info + country + city + area)
    city = " Beijing "
#调用内部函数
    func_son("ChaoYang ")

func_father("China ")
#例2的输出结果为:Adress : China Shanghai ChaoYang 
例3:
info = "Adress : "
def func_father(country):
    def func_son(area):
        city= "Shanghai " #此处的city变量,覆盖了父函数的city变量
        print(info + country + city + area)
    city = " Beijing "
#调用内部函数
func_son("ChaoYang ") #在函数体外调用函数

func_father("China ")
#例3的输出结果为:name 'func_son' is not defined


三、变量的作用域:
1、变量的作用域就是一个变量的命名空间
2、程序的变量并不是在任何位置都可以访问的,访问权限决定于这个变量是在哪里赋值的。代码中变量被赋值的位置决定哪些范围的对象可以访问这个变量,这个范围就是命名空间
3、变量的作用域决定了在哪一部分程序可以访问哪个特定的变量名称

Python的作用域一共有4种,分别是:

扫描二维码关注公众号,回复: 2746514 查看本文章

1、L (Local) 局部作用域

2、E (Enclosing) 闭包函数外的函数中

3、G (Global) 全局作用域

4、B (Built-in) 内建作用域
查找规则为:以 L –> E –> G –>B 的规则查找,即:在局部找不到,便会去局部外的局部找(例如闭包),再找不到就会去全局找,再者去内建中找。
例4:
x = int(2.9)         # 内建作用域
 
g_count = 0           # 全局作用域
def outer():
    o_count = 1       # 闭包函数外的函数中
    def inner():
        i_count = 2   # 局部作用域
注:Python 中只有模块(module),类(class)以及函数(def、lambda)才会引入新的作用域,其它的代码块(如 if/elif/else/、try/except、for/while等)是不会引入新的作用域的,也就是说这些语句内定义的变量,外部也可以访问
 
四、局部变量
1、定义在函数内部的变量拥有一个局部作用域,定义在函数外的拥有全局作用域
2、局部变量只能在函数体内被访问,超出函数体的范围访问就会报错, 函数体外是无法访问到函数内部的局部变量的
例5:
def function():
    x = 100
    print(x)#在函数内访问
function()

#例5的输出结果为:100
例6:
def function():
    x = 100
    print("变量x:" ,x) #
print("函数体外访问x:",x)
function()

#例5的输出结果为:NameError: name 'x' is not defined

五、全局变量
1、在函数外,一段代码最开始赋值的变量可以被多个函数引用,这就是全局变量
2、全局变量可以在整个程序范围内访问
例7:

number = 0                               #这是一个全局变量
def function(num_1,num_2):
    number = num_1 + num_2               #number在这里是一个局部变量
    print("函数内是局部变量:",number)
    return number
def func():
    print("number的值是:",number)
    return number
print("函数求和结果:",function(10,20))
func()
print("函数外是全局变量:",number)

#上面代码的输出结果为:
函数内是局部变量: 30
函数求和结果: 30
number的值是: 0
函数外是全局变量: 0
由上面的代码可以看出:
全局变量可以在全局使用,在函数体中更改全局变量的值不会更改函数体外全局变量的值,不会影响到全局变量在其他函数内或其他语句中的使用,这是因为调用function函数时创建了新的命名空间,它作用于function函数代码块,只会在这个作用域内起作用
注:要将全局变量变为局部变量,只需要在函数体中定义一个和局部变量名称一样的变量即可( 此方法不会修改到全局变量的值)


3、global关键字:
1、global关键字的作用为将函数体的局部变量变为全局变量: 在函数体外可以访问定义在函数体内的变量
2、要在函数体内将某个变量定义为全局变量,在需要被定义的变量前加一个关键字global即可
3、在函数体中定义global变量后,在函数体中对变量做的其他操作也是全局性的
4、以使用同一个global语句指定多个全局变量。例如global x, y, z。
5、如果要修改嵌套作用域(enclosing 作用域,外层非全局作用域)中的变量则需要 nonlocal关键字了
例8:
number = 0 #这是一个全局变量
print("这里输出调用前的number值:",number)
def function():
    global number
    number = 200
    number += 100    #函数体内重新定义number
    print("函数内是局部变量:",number)
    return number
def func():
    print("其他函数内number的值是:",number)
    return number
function()
func()
print("函数外number的值:",number)

#上面代码的输出结果为:
这里输出调用前的number值: 0
函数内是局部变量: 300
其他函数内number的值是: 300
函数外number的值: 300

例9:

def function():
    global x
    x = 100
    print(x)


function()
print(x)

#上面函数的输出结果为:100,100
例10:
def outer():
    num = 10
    def inner():
        nonlocal num   # nonlocal关键字声明
        num = 100
        print(num)
    inner()
    print(num)
outer()

#上面函数的输出结果为:100,100


六、有返回值函数和无返回值函数
1、若定义函数时没有使用return语句,则默认返回一个None。
2、要返回一个None,可以只写一个return
3、要返回具体的数值,就需要在ruturn后面加上需要返回的内容
4、对于函数来说,使用return语句可以向外提供该函数执行的一些结果;对于函数的调用者来说,是否可以使用函数中执行的一些操作结果,就在与函数是否使用return语句返回了对应的执行结果
5、在python中,有的函数会产生结果(如数学函数),我们称这类函数为有返回值函数;有的函数执行一些动作后不返回任何值,我们就称这类函数为无返回值函数
6、 return语句表示函数体的结束,所以return语句必须写在函数体的最后一行
例11:
def func_1():
    print("func_1函数不写return语句")
def func_2():
    print("func_2函数只写return语句,不返回具体内容")
    return
def func_3():
    x = 10
    y = 20
    z = x + y
    print("func_3函数写return语句,并返回具体内容")
    return z

print("函数func_1调用结果:",func_1())
print("函数func_2调用结果:",func_2())
print("函数func_3调用结果:",func_3())

#上面代码的执行结果为:
func_1函数不写return语句
函数func_1调用结果: None
func_2函数只写return语句,不返回具体内容
函数func_2调用结果: None
func_3函数写return语句,并返回具体内容
函数func_3调用结果: 30
由上面的代码可知:定义函数时不写return或只写一个return语句返回的都是一个None,如果写了返回的具体内容,调用函数时就会获得具体的内容

猜你喜欢

转载自blog.csdn.net/qq_39314932/article/details/79858372