Python-命名空间和变量作用域详解(global、nonlocal)

怼烎@ 2022-12-17 11:57 267阅读 0赞

目录

上篇文章思考题

命名空间

作用域

全局变量与局部变量

就近原则

只读问题

关键字

全部代码

总结

思考题


上篇文章思考题

Python-函数基础总结与内置函数

1.

def plus(*args):
return sum(args)

print(plus(1, 2, 3))
print(plus(2, 4, 6, 8, 10))

结果:

6

30

2.

def power(x=2, n):
return x ** n

结果:

  1. def power(x=2, n):
  2. ^

SyntaxError: non-default argument follows default argument

注意:有默认值的参数必须在无默认值参数的后面

可写为:

def power(n, x=2):
return x ** n

对于包含 参数有默认值的 函数,而且已经调用了,不易改动,不方便添加不含默认值的参数,保证健壮性,只能添加默认值。

power(x,n=2)添加y参数时power(x,n=2,y)是不对的,只能是power(x,n=2,y=None),y可以赋值为其他默认值。

命名空间

命名空间(namespace )是一个从名字到对象的映射,当前,大部分命名空间都由 Python 字典实现。

同命名空间中的名称之间绝对没有关系,例如,两个不同的模块都可以定义一个 maximize 函数而不会产生混淆,当然,模块的用户必须在其前面加上模块名称。类似一个文件夹内不能有重复名称的文件,但是,不同的文件夹内可以有相同名称的文件。

在不同时刻创建的命名空间拥有不同的生存期。包含内置名称的命名空间是在 Python 解释器启动时创建的,永远不会被删除。

模块的全局命名空间在模块定义被读入时创建,通常,模块命名空间也会持续到解释器退出。

作用域

一个 作用域是一个命名空间可直接访问的 Python 程序的文本区域。 这里的 “可直接访问” 意味着对名称的非限定引用(非限定引用就是你没加关键字,Python默认情况下)会尝试在命名空间中查找名称

  • L(Local):最内层,包含局部变量,比如一个函数/方法内部。
  • E(Enclosing):包含了非局部(non-local)也非全局(non-global)的变量。比如两个嵌套函数,一个函数(或类) A 里面又包含了一个函数 B ,那么对于 B 中的名称来说 A 中的作用域就为 nonlocal。
  • G(Global):当前脚本的最外层,比如当前模块的全局变量。
  • B(Built-in): 包含了内建的变量/关键字等。

搜索顺序:L –> E –> G –>B

接下来我们就不说B了,随时都能访问,应该没有什么疑惑。

全局变量与局部变量

我们定义一个全局变量name,Show函数中定义一个局部变量name。

  1. name = 'lady_killer'
  2. def Show():
  3. university = 'BUPT'
  4. def show_nonlocal():
  5. print('show_nonlocal:', university)
  6. print('show_nonlocal:', name)
  7. def show_global():
  8. print('show_global:', university)
  9. print('show_global:', name)
  10. show_nonlocal()
  11. show_global()
  12. print('local:', university)
  13. # NameError: name 'university' is not defined
  14. # print(university)
  15. Show()
  16. print('gloabal:', name)

结果:

show_nonlocal: BUPT
show_nonlocal: lady_killer
show_global: BUPT
show_global: lady_killer
local: BUPT
gloabal: lady_killer

当然,局部作用域外不能访问局部变量

Traceback (most recent call last):
File “learnarea.py”, line 28, in
print(university)
NameError: name ‘university’ is not defined

就近原则

接下来我们就看看同名的情况。

我们对show函数进行一下修改,在局部作用域增加同名的变量。

  1. def Show():
  2. university = 'BUPT'
  3. name = 'YuBo'
  4. def show_nonlocal():
  5. university = 'bupt'
  6. name = 'frankyu'
  7. print('show_nonlocal:', university)
  8. print('show_nonlocal:', name)
  9. def show_global():
  10. print('show_global:', university)
  11. print('show_global:', name)
  12. show_nonlocal()
  13. show_global()
  14. print('local:', university)

结果:

show_nonlocal: bupt
show_nonlocal: frankyu
show_global: BUPT
show_global: YuBo
local: BUPT
gloabal: lady_killer

可以看到按照L->E->G顺序查找,即就近原则

只读问题

我们尝试增加一个全局变量num,并在函数内进行复合的赋值操作,关于操作符可查看Python-操作符总结(逻辑、位、算术、比较、赋值操作符及操作符优先级)。

  1. num = 1
  2. def Show():
  3. university = 'BUPT'
  4. name = 'YuBo'
  5. # UnboundLocalError: local variable 'num' referenced before assignment
  6. num += 1

结果:

Traceback (most recent call last):
File “learnarea.py”, line 35, in
Show()
File “learnarea.py”, line 16, in Show
num += 1
UnboundLocalError: local variable ‘num’ referenced before assignment

num += 1,即 num = num + 1,在找后面的num时没有去全局变量寻找,而是认为局部变量,但是我们没有定义局部变量num,所以就是赋值前引用,如果我们在num+=1前使用num=2之类的进行定义num,就不会出错了,但如果我们想使用全局变量该怎么办呢?请继续看。

关键字

global关键字用于使用全局变量

nonlocal关键字用于使用嵌套外部函数变量

  1. def Show():
  2. university = 'BUPT'
  3. global name
  4. name += 'YuBo'
  5. # UnboundLocalError: local variable 'num' referenced before assignment
  6. # num += 1
  7. def show_nonlocal():
  8. nonlocal university
  9. university += 'bupt'
  10. name = 'frankyu'
  11. print('show_nonlocal:', university)
  12. print('show_nonlocal:', name)
  13. def show_global():
  14. print('show_global:', university)
  15. print('show_global:', name)

结果:

show_nonlocal: BUPTbupt
show_nonlocal: frankyu
show_global: BUPTbupt
show_global: lady_killerYuBo
local: BUPTbupt
gloabal: lady_killerYuBo

全部代码

  1. """
  2. --coding:utf-8--
  3. @File: learnarea.py
  4. @Author:frank yu
  5. @DateTime: 2020.10.23 15:00
  6. @Contact: frankyu112058@gmail.com
  7. @Description: 学习变量作用域
  8. """
  9. name = 'lady_killer'
  10. num = 1
  11. def Show():
  12. university = 'BUPT'
  13. global name
  14. name += 'YuBo'
  15. # UnboundLocalError: local variable 'num' referenced before assignment
  16. # num += 1
  17. def show_nonlocal():
  18. nonlocal university
  19. university += 'bupt'
  20. name = 'frankyu'
  21. print('show_nonlocal:', university)
  22. print('show_nonlocal:', name)
  23. def show_global():
  24. print('show_global:', university)
  25. print('show_global:', name)
  26. show_nonlocal()
  27. show_global()
  28. print('local:', university)
  29. # NameError: name 'university' is not defined
  30. # print(university)
  31. Show()
  32. print('gloabal:', name)

总结

  • 局部作用域外不能访问局部变量
  • 非限定引用下,按照L->E->G顺序查找,即就近原则
  • 非限定引用下,无法在局部对全局变量进行修改
  • 如果要修改局部外的变量,可以使用global、nonlocal分别对全局变量和嵌套外部函数的变量进行修改
  • 建议不在局部使用和外部相同的变量名称

思考题

以下代码。结果是什么?

  1. send_packet = 56
  2. def test(i):
  3. global send_packet
  4. if i > 5:
  5. send_packet = 1
  6. return send_packet
  7. print(test(2))
  8. print(test(6))

如果是这样呢?

  1. send_packet = 56
  2. def test(i):
  3. global send_packet
  4. if i > 5:
  5. send_packet = 1
  6. return send_packet
  7. print(test(6))
  8. print(test(2))

答案见:Python-面向对象编程总结(类、对象、派生、继承、方法、内置函数等)

更多python相关内容:【python总结】python学习框架梳理

本人b站账号:lady_killer9

有问题请下方评论,转载请注明出处,并附有原文链接,谢谢!如有侵权,请及时联系。如果您感觉有所收获,自愿打赏,可选择支付宝18833895206(小于),您的支持是我不断更新的动力。

发表评论

表情:
评论列表 (有 0 条评论,267人围观)

还没有评论,来说两句吧...

相关阅读