Python变量作用域

所谓作用域(Scope), 就是变量的作用范围, 就是变量可以在哪个范围内使用. 有些变量可以在整段代码的任意位置使用, 有些变量只能在函数内部使用, 有些变量只能在for循环内部使用.

变量的作用域由变量的定义位置决定, 在不同位置定义的变量, 它的作用域是不一样的.

局部变量

在函数内部定义的变量, 它的作用域也仅限于函数内部, 这样的变量称为局部变量(Local Variable).

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

值得一提的是, 函数的参数也属于局部变量, 只能在函数内部使用.

全局变量

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

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

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

  • 在函数体的外部定义的变量, 一定是全局变量;

Example:

# 定义全局变量
msg = 'hello, world'
def showMsg():
    # 在函数内部使用全局变量
    print('在函数体内, msg = ', msg)

showMsg()
# 在函数外部使用全局变量
print('在函数体外, msg = ', msg)
  • 在函数体内定义全局变量, 即使用global关键字对变量进行修饰后, 该变量就会称为全局变量.

Example:

def showMsg():
    # 在函数内部定义全局变量
    global msg
    msg = 'hello, world'

    # 在函数内部使用全局变量
    print('在函数内部, msg = ', msg)

showMsg()
# 在函数外部使用全局变量
print('在函数外部, msg = ', msg)

注意

在使用global关键字修饰变量名时, 不能直接给变量赋值, 否则会引发语法错误. 要先声明, 再赋值.

全局变量和局部变量的同名问题

全局变量可以在程序中任何位置被访问甚至修改, 但是, 当函数中定义了和全局变量变量同名的局部变量时, 那么在当前函数中, 无论是访问还是修改该同名变量, 操作的都是局部变量, 而不是全局变量.

注解

当函数内部的局部变量和函数外部的全局变量同名时, 在函数内部, 局部变量会”遮蔽”同名的全局变量.

Example:

# 定义全局变量
msg = 'hello, world'
def showMsg():
    print(msg)
    # 定义同名的局部变量
    msg = 'ABC'

showMsg()

执行上面的程序, 运行报错:

UnboundLocalError: local variable 'msg' referenced before assignment

意思是: 所访问的变量msg还未定义, 这是什么原因呢?

Python语法规定, 在函数内部对不存在的变量赋值时, 默认就是定义新的局部变量. 在上面的程序中, 在函数的内部定义了一个新的msg局部变量, 由于该局部变量和全局变量msg同名, 所以局部变量就是”遮蔽”全局msg变量, 再加上局部变量msgprint(msg)之后才被初始化, 违反了”先定义后使用”的原则, 因此程序会报错.

注解

Python程序在运行时, 先导入整个程序, 再执行. 很多初始化工作在导入时就完成了(比如上面的示例程序中, 局部变量”遮蔽”全局变量的工作).

那么, 如果就是想在函数中访问甚至修改被”遮蔽”的变量, 怎么办呢? 可以采取以下两种方法:

  • 如果希望程序依然能够访问msg全局变量, 且在函数中重新定义msg局部变量, 也就是在函数中可以访问被遮蔽的全局变量, 此时可以通过globals()函数来实现.

Example:

msg = 'global'
def showMsg():
    # 通过globals()函数访问甚至修改全局变量
    print(globals()['msg'])
    globals()['msg'] = 'Hello, world'
    # 定义局部变量
    msg = 'local'

showMsg()
print(msg)

运行结果为:
global
Hello, world
  • 在函数中用global语句声明全局变量, 这样在函数中对该变量的操作都是对全局变量的操作, 赋值不会定义全局变量.

Example:

msg = 'global'
def showMsg():
    global msg
    # 访问全局变量
    print(msg)
    # 修改全局变量的值
    msg = 'Hello, world'

showMsg()
print(msg)

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

在一些特殊场景中, 我们可能需要获取某个作用域内所有的变量, Python提供了以下三种方式:

  • globals()函数

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

注意

globals()函数返回的字典中, 会默认包含有很多变量, 这些都是Python主程序设置的.

我们甚至可以通过globals()函数, 以键值对的形式访问变量, 如果需要, 还可以修改它的值.

Exmaple:

msg = 'hello, world'
print(globals())

# 通过globals()函数, 以键值对的形式访问变量
print('msg = ', globals()['msg'])
# 通过globals()函数, 以键值对的形式修改变量的值
globals()['msg'] = 'ABC'
print(msg)
  • locals()函数

locals()函数也是Python内置函数之一, 通过调用该函数, 可以得到一个包含当前作用域内所有变量的字典. 这里所谓的”当前作用域”, 指的是在函数内部调用locals()函数, 会获得包含所有局部变量的字典; 而在全局作用域中调用locals()函数, 其功能和globals()函数相同.

  • vars(object)

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