Python中全局变量和局部变量的区别以及使用

0. 前置知识

0.1 作用域

所谓作用域(Scope),就是变量的有效范围,就是变量可以在哪个范围以内使用

  • 有些变量可以在整段代码的任意位置使用
  • 有些变量只能在函数内部使用
  • 有些变量只能在 for 循环内部使用

变量的作用域由变量的定义位置决定,在不同位置定义的变量,它的作用域是不一样的。在Python语言中,变量一般根据作用域被划分为两种:

  1. 局部变量
  2. 全局变量。

1. 局部变量

定义:在函数内部定义的变量,它的作用域也仅限于函数内部,出了函数就不能使用了,我们将这样的变量称为局部变量(Local Variable)。

理论:要知道,当函数被执行时,Python 会为其分配一块临时的存储空间,所有在函数内部定义的变量,都会存储在这块空间中。而在函数执行完毕后,这块临时存储空间随即会被释放并回收,该空间中存储的变量自然也就无法再被使用。

例子1

>>> def demo():
...     text = "在函数内部声明了一个变量,这个变量就是局部变量"
...     print(text)
... 
>>> demo()
在函数内部声明了一个变量,这个变量就是局部变量
>>> print(text)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'text' is not defined

在上面的例子中,text变量的声明(创建)是在函数demo中,所以它是一个局部变量,所以在函数外面是不可以直接使用的。

如果试图在函数外部访问其内部定义的变量,Python 解释器会报 NameError 错误,并提示我们没有定义要访问的变量,这也证实了当函数执行完毕后,其内部定义的变量会被销毁并回收

1.1 问题一:同名变量

我们思考一个问题,如果在函数外部和函数内部都定义了同名变量,那么会怎么样呢?

>>> def demo():
...     text = "在函数内部声明了一个变量,这个变量就是局部变量"
...     print(text)
... 
>>> text = "在函数外部创建了同名变量"
>>> demo()
在函数内部声明了一个变量,这个变量就是局部变量
>>> print(text)
在函数外部创建了同名变量

很明显,因为在函数外部定义了text变量,所以外部在调用text时不会调用函数内部的text而是调用前面我们定义的text

1.2 问题二:函数调用函数外的变量

那函数可以直接调用函数外的变量吗?

>>> def demo():
...     print(f"函数直接调用外部变量 [{text}]")
... 
>>> text = "在函数外部创建的变量"
>>> demo()
函数直接调用外部变量 [在函数外部创建的变量]

可以看到,函数在直接定义时是可以调用外部变量的,且不会报错。当我们调用函数时,只要保证其调用的外部变量存在,则不会报错,否则就会报错。下面是报错的情况:

>>> def demo():
...     print(f"直接调用main中的变量: {text}")
... 
>>> # 此时main函数中并没有text变量
>>> demo()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in demo
NameError: name 'text' is not defined

2. 全局变量

除了在函数内部定义变量,Python 还允许在所有函数的外部定义变量,这样的变量称为全局变量(Global Variable)。

和局部变量不同,全局变量的默认作用域是整个程序,即全局变量既可以在各个函数的外部使用,也可以在各函数内部使用

定义全局变量的方式有以下 2 种:

  1. 在main函数中定义的变量
  2. 在函数体内声明的全局变量

2.1 第一种声明方式 —— 在main函数中定义的变量

其实我们在问题1.1和问题1.2中已经写了,在函数体外定义的变量其实就是全局变量,也就是在main函数中定义的变量就是全局变量。

举个例子:

>>> global_var_1 = "这是一个全局变量"
>>> global_var_2 = ["这也是一个全局变量", 123]
>>> # 再定义一个函数和局部变量
>>> def demo(local_var_1, local_var_2):
...     local_var_3 = "这是一个局部变量"
...     local_var_4 = ("这也是一个局部变量", 456)
...     print(local_var_1)
...     print(local_var_2)
...     print(local_var_3)
...     print(local_var_4)
...     print("局部变量打印完毕")
... 
>>> demo(1, 2)  # 这里传给函数的两个形参是全局变量
1
2
这是一个局部变量
('这也是一个局部变量', 456)
局部变量打印完毕
>>> global_var_1
'这是一个全局变量'
>>> global_var_2
['这也是一个全局变量', 123]

2.2 第二种声明方式 —— 在函数体内声明的全局变量

在函数体内也是可以创建全局变量的,步骤如下:

def 函数名称(形参1, 形参2, ...):
	# 1. 需在变量前使用关键字`global`进行声明,这样一个全局变量就创建好了
	gloabl 全局变量名
	# 2. 声明完毕后赋值
	全局变量名 =# 3. 在调用函数之后,在函数中声明的全局变量也就被创建了,否则不会创建的
函数名称(传参1,传参2)

# 4. 可以任意使用那个全局变量了
print(全局变量)

2.2.1 正确

>>> def demo():
...     # 声明一个局部变量var_1
...     var_1 = "This is a local variable"
...     # 1. 先用global关键词进行全局变量的声明
...     global var_2
...     # 2. 再对全局变量进行赋值
...     var_2 = "This is a global variable"
...     print(f"[在函数内使用] local_var: {var_1}")
...     print(f"[在函数内使用] global_var: {var_2}")
... 
>>> demo()
[在函数内使用] local_var: This is a local variable
[在函数内使用] global_var: This is a global variable
>>> # 在main函数中调用函数生成的全局变量
>>> print(f"[在main函数中使用] global_var: {var_2}")
[在main函数中使用] global_var: This is a global variable

2.2.2 错误1 —— 没有调用函数就使用函数内部将会创建的全局变量

如果不调用函数就直接使用函数中创建的全局变量,是会报错的,如下:

>>> def demo():
...     # 创建一个局部变量
...     var_1 = "局部变量123"
...     # 1. 先声明是全局变量
...     global var_2
...     # 2. 再进行赋值操作
...     var_2 = "全局变量456"
... 
>>> # 如果不调用函数直接使用在函数中生成的全局变量
>>> print(f"var_2: {var_2}")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'var_2' is not defined
>>> # 必须先调用函数后,函数中的全局变量才能生成
>>> demo()
>>> print(f"var_2: {var_2}")
var_2: 全局变量456

2.2.3 错误2 —— 使用global关键字声明全局变量时直接对其进行赋值

>>> def demo():
...     # 如果声明时直接赋值
...     global var_1 = "这是一个全局变量,但是在声明时就赋值了"
  File "<stdin>", line 3
    global var_1 = "这是一个全局变量,但是在声明时就赋值了"
                 ^
SyntaxError: invalid syntax

2.2.4 思考 —— 多个函数对同一变量进行全局变量声明会报错吗?

看例子,很容易:

>>> def func_1():
...     global var_1
...     var_1 = "abc"
...     print(f"[function_1]全局变量var_1已经创建: {var_1}")
... 
>>> def func_2():
...     global var_1
...     var_1 = "123"
...     print(f"[function_2]全局变量var_1已经创建: {var_1}")
... 
>>> # 其实没什么影响,和赋值的原理是一样的
>>> # 先调用func_1
>>> func_1()
[function_1]全局变量var_1已经创建: abc
>>> var_1
'abc'
>>> # 再调用func_2
>>> func_2()
[function_2]全局变量var_1已经创建: 123
>>> var_1
'123'

3. 获取指定作用域范围中的变量

在一些特定场景中,我们可能需要获取某个作用域内(全局范围内或者局部范围内)所有的变量,Python 提供了以下 3 种方式:

  1. globals()函数
  2. locals()函数
  3. vars(object)函数

3.1 globals()函数

globals()函数为 Python 的内置函数,它可以返回一个包含全局范围内所有变量的字典,该字典中的每个键值对,键为变量名,值为该变量的值

>>> globals()
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'demo': <function demo at 0x7ff433a520d0>, 'var_2': '全局变量456', 'func_1': <function func_1 at 0x7ff433a52280>, 'func_2': <function func_2 at 0x7ff433a52160>, 'var_1': '123'}

注意,globals()函数返回的字典中,会默认包含有很多变量,这些都是 Python 主程序内置的,不用理会它们。

可以看到,通过调用 globals() 函数,我们可以得到一个包含所有全局变量的字典。并且,通过该字典,我们还可以访问指定变量,甚至如果需要,还可以修改它的值。例如,在上面程序的基础上,添加如下语句:

>>> print(globals()["var_2"])
全局变量456
>>> globals()["var_2"] = "对这个全局变量进行重新赋值!"
>>> print(globals()["var_2"])
对这个全局变量进行重新赋值!
>>> globals()
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'demo': <function demo at 0x7ff433a520d0>, 'var_2': '对这个全局变量进行重新赋值!', 'func_1': <function func_1 at 0x7ff433a52280>, 'func_2': <function func_2 at 0x7ff433a52160>, 'var_1': '123'}

3.2 locals()函数

locals() 函数也是 Python 内置函数之一,通过调用该函数,我们可以得到一个包含当前作用域内所有变量的字典。这里所谓的“当前作用域”指的是:

  • 在函数内部调用 locals() 函数,会获得包含所有局部变量的字典
  • 而在全局范文内调用 locals() 函数,其功能和 globals() 函数相同。
>>> def demo(a, b):
...     c = 10  # 定义局部变量
...     global d  # 声明全局变量
...     d = 100
...     print(locals())  # 查看该函数的局部变量
...     return a + b + c + d
... 
>>> # 定义一些全局变量
>>> aaa = 123
>>> bbb = 456
>>> # 查看全局变量
>>> globals()
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'demo': <function demo at 0x7f1132cbd0d0>, 'aaa': 123, 'bbb': 456}
>>> # 查看局部变量
>>> locals()
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'demo': <function demo at 0x7f1132cbd0d0>, 'aaa': 123, 'bbb': 456}
>>> # 调用函数
>>> demo(1, 2)
{'a': 1, 'b': 2, 'c': 10}
113
>>> # 查看全局变量
>>> globals()
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'demo': <function demo at 0x7f1132cbd0d0>, 'aaa': 123, 'bbb': 456, 'd': 100}
>>> # 查看局部变量
>>> locals()
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'demo': <function demo at 0x7f1132cbd0d0>, 'aaa': 123, 'bbb': 456, 'd': 100}

Note:

  • 当使用 locals() 函数获得所有局部变量组成的字典时,可以向 globals() 函数那样,通过指定键访问对应的变量值,但无法对变量值做修改

3.3 var(object)函数

vars() 函数也是 Python 内置函数,其功能是返回一个指定 object 对象范围内所有变量组成的字典。如果不传入object 参数,vars() 和 locals() 的作用完全相同

>>> class A:
...     def __init__(self, a, b, c):
...             self.a = a
...             self.b = b
...             self.c = c
...     name = "Leovin"
...     school = "xxx University"
... 
>>> print(f"vars(A): {vars(A)}")
vars(A): {'__module__': '__main__', '__init__': <function A.__init__ at 0x7fd201d5e160>, 'name': 'Leovin', 'school': 'xxx University', '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None}
>>> print(vars())
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'A': <class '__main__.A'>}
>>> print(globals())
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'A': <class '__main__.A'>}
>>> print(locals())
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'A': <class '__main__.A'>}
>>> def func(a, b):
...     c = 1
...     global d
...     d = 10
...     return a + b + c + d
... 
>>> vars(func)
{}
>>> vars(func(1, 2))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: vars() argument must have __dict__ attribute
>>> vars()
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'A': <class '__main__.A'>, 'func': <function func at 0x7fd201d5e0d0>, 'd': 10}
>>> vars(A)
mappingproxy({'__module__': '__main__', '__init__': <function A.__init__ at 0x7fd201d5e160>, 'name': 'Leovin', 'school': 'xxx University', '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None})
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值