码农行者 码农行者
首页
  • Python

    • 语言特性
    • Django相关
    • Tornado
    • Celery
  • Golang

    • golang学习笔记
    • 对比python学习go
    • 模块学习
  • JavaScript

    • Javascript
  • 数据结构预算法笔记
  • ATS
  • Mongodb
  • Git
云原生
运维
垃圾佬的快乐
  • 数据库
  • 机器学习
  • 杂谈
  • 面试
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

DeanWu

软件工程师
首页
  • Python

    • 语言特性
    • Django相关
    • Tornado
    • Celery
  • Golang

    • golang学习笔记
    • 对比python学习go
    • 模块学习
  • JavaScript

    • Javascript
  • 数据结构预算法笔记
  • ATS
  • Mongodb
  • Git
云原生
运维
垃圾佬的快乐
  • 数据库
  • 机器学习
  • 杂谈
  • 面试
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 「Python Tips」 - Python 变量作用域详解

  • 开发语言
  • Python
  • 语言特性
DeanWu
2022-03-14
目录

「Python Tips」 - Python 变量作用域详解

今天在 FastAPI 的一个交流群中回答了个网友的问题,发现自己对 Python 作用域已忘记大半,特意查了些资料,记录备查,希望对朋友们理解有帮助。

阅读本文,你可以了解如下内容: white-list-template.xlsx

Python 中常用的变量作用域有这么几种:局部变量、非局部变量、全局变量,下面我们来举例说明。

# 局部变量

在函数体或局部范围内声明的变量称为局部变量。参考如下实例:

def foo():
    y = "local"
    print(y)

y = "global"
foo()
print(y)

# local
# global
1
2
3
4
5
6
7
8
9
10

局部变量尽在局部作用域内有效,可以看到上边代码块有两个同名的变量 y,函数内的局部变量 y 并不会影响全局变量 y。

# 非局部变量

Python 3 中增加了关键字 nonlocal 用来创建非局部变量,主要用在未定义局部变量的嵌套函数内。参考如下实例:

def outer():
    x = "local"
    def inner():
        nonlocal x
        print("inner:", x)
        x = "nonlocal"

    inner()
    print("outer:", x)

x = 'global'
outer()
print('glabal:', x)

# inner: local
# outer: nonlocal
# glabal: global
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

nolocal 关键字会向上一个作用域查找,取最近的一个变量定义。如上代码块中,x 向上最近的定义是 x="local",并没有取局部变量 x (严格来说 inner 函数中的 x 已不是局部变量,而是修改赋值的 outer 函数中的变量 x)和全局的变量 x。

# 全局变量

在 Python 中,在函数之外或在全局范围内声明的变量称为全局变量。全局变量允许在函数内部和外部访问,但是不允许在函数内部修改。参考如下实例:

x = "global"

def foo():
    print("x inside:", x)

foo()
print("x outside:", x)
# ('x inside:', 'global')
# ('x outside:', 'global')

def foo2():
    x = x * 2
    print(x)

foo2()
# UnboundLocalError: local variable 'x' referenced before assignment
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

全局变量不允许在函数内部做修改,如需要,则要用到关键字 global 。

x = "global"

def foo():
    global x
    x = x * 2
    print("x inside:", x)

foo()
print("x outside:", x)
# x inside: globalglobal
# x outside: globalglobal
1
2
3
4
5
6
7
8
9
10
11

global 关键字和 nonlocal 类似也是从其他作用域搜索变量定义,但它仅仅是搜索全局作用域内的变量定义。参考如下实例:

def outer():
    x = "local"
    def inner():
        global x
        print("inner:", x)
        x = "nonlocal"

    inner()
    print("outer:", x)


x = 'global'
outer()
print('glabal:', x)
# inner: global
# outer: local
# glabal: nonlocal
def foo2():
    global x
    x = x * 2
    print("x inside:", x)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

inner 函数中 global 定义的变量 x,取的是全局变量中的变量 x。

# 工具模块 dis

官方提供了一个工具模块 dis,可以查看函数在 Python 解释器执行的字节码。我们可以通过它来看具体的作用域调用过程,如下:

$ python3
Python 3.8.10 (default, May  4 2021, 03:05:50)
[Clang 12.0.0 (clang-1200.0.32.29)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> x = "global"
>>> def foo():
...     print("x inside:", x)
...
>>> def foo1():
...     global x
...     print("x inside:", x)
...
>>> def foo2():
...     global x
...     x = x * 2
...     print("x inside:", x)
...
>>> def foo3():
...     x = x * 2
...     print("x inside:", x)
...
>>> from dis import dis
>>> dis(foo)
  2           0 LOAD_GLOBAL              0 (print)
              2 LOAD_CONST               1 ('x inside:')
              4 LOAD_GLOBAL              1 (x)
              6 CALL_FUNCTION            2
              8 POP_TOP
             10 LOAD_CONST               0 (None)
             12 RETURN_VALUE
>>> dis(foo1)
  3           0 LOAD_GLOBAL              0 (print)
              2 LOAD_CONST               1 ('x inside:')
              4 LOAD_GLOBAL              1 (x)
              6 CALL_FUNCTION            2
              8 POP_TOP
             10 LOAD_CONST               0 (None)
             12 RETURN_VALUE
>>> dis(foo2)
  3           0 LOAD_GLOBAL              0 (x)
              2 LOAD_CONST               1 (2)
              4 BINARY_MULTIPLY
              6 STORE_GLOBAL             0 (x)

  4           8 LOAD_GLOBAL              1 (print)
             10 LOAD_CONST               2 ('x inside:')
             12 LOAD_GLOBAL              0 (x)
             14 CALL_FUNCTION            2
             16 POP_TOP
             18 LOAD_CONST               0 (None)
             20 RETURN_VALUE
>>> dis(foo3)
  2           0 LOAD_FAST                0 (x)
              2 LOAD_CONST               1 (2)
              4 BINARY_MULTIPLY
              6 STORE_FAST               0 (x)

  3           8 LOAD_GLOBAL              0 (print)
             10 LOAD_CONST               2 ('x inside:')
             12 LOAD_FAST                0 (x)
             14 CALL_FUNCTION            2
             16 POP_TOP
             18 LOAD_CONST               0 (None)
             20 RETURN_VALUE
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64

可以看到在函数读取全局变量时,字节码是完全一致的,所以他们的行为也是一致的。当函数在修改全局变量时,字节码明显不一样,使用 global定义的会先LOAD_GLOBAL,dis 模块的更多用法可参考 Python 官方文档 (opens new window)。

# 总结

至此,Python 常用的变量作用域我们便说完了。总结下,局部变量只能在定义的代码块作用域中访问修改。非局部变量向上查找最近的变量定义,可访问可修改。全局变量可以在全局代码块访问和修改,只能在函数内访问不能修改。

除了上边我们说的,Python 还有内部作用域和内置作用域。顾名思义,内部就是多层函数嵌套时,作用域的查找是由内而外的,中间层的作用域就是内部作用域。内置作用域则是 Python 自己内置的一些变量关键字的作用域,由 Python 解释器内部使用。

我是DeanWu,一个努力成为真正SRE的人。

关注公众号「码农吴先生」, 可第一时间获取最新文章。回复关键字「go」「python」获取我收集的学习资料,也可回复关键字「小二」,加我wx拉你进技术交流群,聊技术聊人生~

# 参考资料

  • https://www.programiz.com/python-programming/global-keyword
  • https://docs.python.org/3/library/dis.html https://docs.python.org/3/faq/programming.html#what-are-the-rules-for-local-and-global-variables-in-python
  • https://docs.python.org/3/faq/programming.html#how-do-i-share-global-variables-across-modules
#Python
上次更新: 2023/03/28, 16:27:19
最近更新
01
chromebox/chromebook 刷bios步骤
03-01
02
redis 集群介绍
11-28
03
go语法题二
10-09
更多文章>
Theme by Vdoing | Copyright © 2015-2024 DeanWu | 遵循CC 4.0 BY-SA版权协议
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式