【测试开发】python系列教程:作用域

r囧r小猫 2023-09-25 19:37 116阅读 0赞

这次我们分享python的作用域


作用域就是一个 Python 程序可以直接访问命名空间的正文区域。

在一个 python 程序中,直接访问一个变量,会从内到外依次访问所有的作用域直到找到,否则会报未定义的错误。

Python 中,程序的变量并不是在哪个位置都可以访问的,访问权限决定于这个变量是在哪里赋值的。

变量的作用域决定了在哪一部分程序可以访问哪个特定的变量名称。Python 的作用域一共有4种,分别是:

有四种作用域:

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

规则顺序: L –> E –> G –> B

在局部找不到,便会去局部外的局部找(例如闭包),再找不到就会去全局找,再者去内置中找。

  1. g_cou = 0 # 全局作用域
  2. def outer():
  3. o_cou = 1 # 闭包函数外的函数中
  4. def inner():
  5. i_cou= 2 # 局部作用域

内置作用域是通过一个名为 builtin 的标准模块来实现的,但是这个变量名自身并没有放入内置作用域内,所以必须导入这个文件才能够使用它。

在Python3.0中,可以使用以下的代码来查看到底预定义了哪些变量:

  1. >>> import builtins
  2. >>> dir(builtins)

结果:

  1. ['ArithmeticError', 'AssertionError', 'AttributeError',
  2. 'BaseException', 'BlockingIOError', 'BrokenPipeError',
  3. 'BufferError', 'BytesWarning', 'ChildProcessError',
  4. 'ConnectionAbortedError', 'ConnectionError',
  5. 'ConnectionRefusedError', 'ConnectionResetError',
  6. 'DeprecationWarning', 'EOFError', 'Ellipsis',
  7. 'EnvironmentError', 'Exception', 'False', 'FileExistsError',
  8. 'FileNotFoundError', 'FloatingPointError', 'FutureWarning',
  9. 'GeneratorExit', 'IOError', 'ImportError', 'ImportWarning',
  10. 'IndentationError', 'IndexError', 'InterruptedError',
  11. 'IsADirectoryError', 'KeyError', 'KeyboardInterrupt',
  12. 'LookupError', 'MemoryError', 'ModuleNotFoundError',
  13. 'NameError', 'None', 'NotADirectoryError', 'NotImplemented',
  14. 'NotImplementedError', 'OSError', 'OverflowError',
  15. 'PendingDeprecationWarning', 'PermissionError',
  16. 'ProcessLookupError', 'RecursionError', 'ReferenceError',
  17. 'ResourceWarning', 'RuntimeError', 'RuntimeWarning',
  18. 'StopAsyncIteration', 'StopIteration', 'SyntaxError',
  19. 'SyntaxWarning', 'SystemError', 'SystemExit',
  20. 'TabError', 'TimeoutError', 'True', 'TypeError',
  21. 'UnboundLocalError', 'UnicodeDecodeError',
  22. 'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError',
  23. 'UnicodeWarning', 'UserWarning', 'ValueError', 'Warning',
  24. 'ZeroDivisionError', '__build_class__', '__debug__',
  25. '__doc__', '__import__', '__loader__', '__name__', '__package__',
  26. '__spec__', 'abs', 'all', 'any', 'ascii', 'bin', 'bool',
  27. 'breakpoint', 'bytearray', 'bytes', 'callable', 'chr',
  28. 'classmethod', 'compile', 'complex', 'copyright',
  29. 'credits', 'delattr', 'dict', 'dir', 'divmod', 'enumerate',
  30. 'eval', 'exec', 'exit', 'filter', 'float', 'format',
  31. 'frozenset', 'getattr', 'globals', 'hasattr', 'hash',
  32. 'help', 'hex', 'id', 'input', 'int', 'isinstance',
  33. 'issubclass', 'iter', 'len', 'license', 'list', 'locals',
  34. 'map', 'max', 'memoryview', 'min', 'next', 'object', 'oct',
  35. 'open', 'ord', 'pow', 'print', 'property', 'quit', 'range',
  36. 'repr', 'reversed', 'round', 'set', 'setattr', 'slice',
  37. 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple',
  38. 'type', 'vars', 'zip']

Python 中只有模块(module),类(class)以及函数(def、lambda)才会引入新的作用域,其它的代码块(如 if/elif/else/、try/except、for/while等)是不会引入新的作用域的,也就是说这些语句内定义的变量,外部也可以访问,如下代码:

  1. >>> if True:
  2. ... a='111'
  3. ...
  4. >>> a
  5. '111'

实例中 a 变量定义在 if 语句块中,但外部还是可以访问的。如果将 a 定义在函数中,则它就是局部变量,外部不能访问:

  1. >>> def aout():
  2. ... b=112
  3. ...
  4. >>> b
  5. Traceback (most recent call last):
  6. File "<stdin>", line 1, in <module>
  7. NameError: name 'b' is not defined

从报错的信息上看,说明了 msg_inner 未定义,无法使用,因为它是局部变量,只有在函数内可以使用。

全局变量和局部变量

定义在函数内部的变量拥有一个局部作用域,定义在函数外的拥有全局作用域。

局部变量只能在其被声明的函数内部访问,而全局变量可以在整个程序范围内访问。调用函数时,所有在函数内声明的变量名称都将被加入到作用域中。

  1. total = 0 # 这是一个全局变量
  2. # 可写函数说明
  3. def sum(arg1, arg2):
  4. # 返回2个参数的和."
  5. total = arg1 + arg2 # total在这里是局部变量.
  6. print("函数内是局部变量 : ", total)
  7. return total
  8. # 调用sum函数
  9. sum(10, 20)
  10. print("函数外是全局变量 : ", total)

结果:

e5f47794997b07da434e1f2547566003.png

global 和 nonlocal关键字

当内部作用域想修改外部作用域的变量时,就要用到 global 和 nonlocal 关键字了。

以下实例修改全局变量 num:

  1. num = 1
  2. def fun1():
  3. global num # 需要使用 global 关键字声明
  4. print(num)
  5. num = 123
  6. print(num)
  7. fun1()
  8. print(num)

结果:

c3ece24000641b85340a09ab59cbd8f6.png

如果要修改嵌套作用域(enclosing 作用域,外层非全局作用域)中的变量则需要 nonlocal 关键字了,如下实例:

  1. def outer():
  2. num = 10
  3. def inner():
  4. nonlocal num # nonlocal关键字声明
  5. num = 100
  6. print(num)
  7. inner()
  8. print(num)
  9. outer()

结果:

674a326098e9a38f837b3099b30cc7c2.png

另外有一种特殊情况,假设下面这段代码被运行:

  1. a = 10
  2. def test():
  3. a = a + 1
  4. print(a)
  5. test()

结果;

3189cb63de57346fdf159692fef1a4a5.png

错误信息为局部作用域引用错误,因为 test 函数中的 a 使用的是局部,未定义,无法修改。如何解决这个问题呢

  1. a = 10
  2. def test():
  3. global a
  4. a = a + 1
  5. print(a)
  6. test()

结果

a2889da43592afd98e415ee423b9e834.png

最后: 下方这份完整的软件测试视频学习教程已经整理上传完成,朋友们如果需要可以自行免费领取【保证100%免费】

在这里插入图片描述

这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴上万个测试工程师们走过最艰难的路程,希望也能帮助到你!

ea309a97fa574feeba0851be84cd3e93.gif

发表评论

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

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

相关阅读