python中全局变量如何在函数中进行修改

最近在将之前写的脚本迁移到python,脚本中需要根据入参来对变量进行赋值,然后再另外一个函数中会用到这个值;按照Objective-C的思维就定义了变量写了脚本,结果跟我的认知不大一样

示范代码

#!/usr/bin/python3
# coding=UTF-8
import shutil
import sys
import os

config = ''
buildEnv =''

def envInit():
    buildEnv = sys.argv[1]
    if buildEnv == 'test':
        config = 'Test
        print(config)
    else:
        config = 'Release'
        print(config)
        
def package():
    cmd = 'config %s' %(config)
    print(cmd)

def exportIpa():
    envInit()
    package()


exportIpa()

  • cmd = 'config %s' %(config)
    执行python3 export_ipa.py test打印cmd输出的是 config 而不是预期的 config Test

问题分析
这里就是变量的作用域问题了,现象上是函数内部的config是局部变量了,而不是我们预期的修改了全局变量config的值

小白就去查了下python的命名空间
python命名空间

python使用命名空间记录变量。python中的命名空间就像是一个dict,key是变量的名字,value是变量的值。

python中,每个函数都有一个自己的命名空间,叫做local namespace,它记录了函数的变量。

python中,每个module有一个自己的命名空间,叫做global namespace,它记录了module的变量,包括 functions, classes 和其它imported modules,还有 module级别的 变量和常量。
还有一个build-in 命名空间,可以被任意模块访问,这个build-in命名空间中包含了build-in function 和 exceptions。

当python中的某段代码要访问一个变量x时,python会在所有的命名空间中寻找这个变量,查找的顺序为:

local namespace - 指的是当前函数或者当前类方法。如果在当前函数中找到了变量,停止搜索
global namespace - 指的是当前的模块。如果在当前模块中找到了变量,停止搜索
build-in namespace - 如果在之前两个namespace中都找不到变量x,python会假设x是build-in的函数或者变量。如果x不是内置函数或者变量,python会报错NameError。

对于闭包来说,这里有一点区别,如果在local namespace中找不到变量的话,还会去父函数的local namespace中找变量。

我们在函数中打印他的locals()

def envInit():
    buildEnv = sys.argv[1]
    if buildEnv == 'test':
        config = 'Test'
        print(config)
        print(locals())
    else:
        config = 'Release'
        print(config)

输出:{'buildEnv': 'test', 'config': 'Test'},果然config是作为envInit函数的局部变量了。这也就是为啥修改了它的值,另外的函数中去输出发现还是初始的值了。

解决方法
既然是命名空间问题,那么我们又想在函数中对全局变量进行修改,同时又避免命名歧义的问题,用global来告诉解释器该变量是全局的。

def envInit():
    global config
    buildEnv = sys.argv[1]
    if buildEnv == 'test':
        config = 'Test'
        print(config)
        print(locals())
        print(globals())
    else:
        config = 'Release'
        print(config)

输出:

# python3 export_ipa.py test
Test
{'buildEnv': 'test'} #函数的局部变量
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x10a2c27b8>, '__spec__': None, '__annotations__': {}, '__builtins__': , '__file__': 'export_ipa.py', '__cached__': None, 'shutil': , 'sys': , 'os': , 
'config': 'Test', 
'buildEnv': '', 
'envInit': , 'package': , 'exportIpa': } # 全局变量
config Test # 输出结果符合预期

可以看到config变量的歧义解决了,在globals变量里;

  • 当函数内的变量跟全局变量名称相同了,当我们进行变量值修改的时候就会有歧义,解释器不知道你究竟是定义了个局部变量并赋值,还是要修改全局变量的值,此时该变量默认是当作函数的局部变量了;对于集合类型的变量如果只是修改集合内的数据则不会有歧义
  • global 关键字允许你修改当前范围之外的变量。它用于创建全局变量并在本地上下文中更改变量
  • 当我们在一个函数之外定义一个变量时,默认情况下它是全局变量。你不必使用 global 关键字

参考文档

  • Python中的命名空间概念
  • python 全局变量引用与修改
  • python global的作用

你可能感兴趣的:(python中全局变量如何在函数中进行修改)