提问



如何在函数中创建或使用全局变量?


如果我在一个函数中创建一个全局变量,我如何在另一个函数中使用该全局变量?我是否需要将全局变量存储在需要访问的函数的局部变量中?

最佳参考


您可以在其他函数中使用全局变量,在每个分配给它的函数中将其声明为global:


globvar = 0

def set_globvar_to_one():
    global globvar    # Needed to modify global copy of globvar
    globvar = 1

def print_globvar():
    print(globvar)     # No need for global declaration to read value of globvar

set_globvar_to_one()
print_globvar()       # Prints 1


我想它的原因是,由于全局变量是如此危险,Python希望通过明确要求global关键字确保你真正知道你正在玩的是什么。


如果要跨模块共享全局变量,请参阅其他答案。

其它参考1


如果我正确理解您的情况,您所看到的是Python处理本地(函数)和全局(模块)命名空间的结果。


说你有这样一个模块:


# sample.py
myGlobal = 5

def func1():
    myGlobal = 42

def func2():
    print myGlobal

func1()
func2()


你可能希望这打印42,但它打印5.正如已经提到的,如果你向func1()添加global声明,那么func2()将打印42。


def func1():
    global myGlobal
    myGlobal = 42


这里发生的是Python假定在函数内的任何位置分配给的任何名称都是该函数的本地名称,除非另有明确说明。如果它只是读取来自一个名称,并且名称不存在于本地,它将尝试在任何包含范围中查找名称(例如模块的全局范围)。


因此,当您为名称myGlobal分配42时,Python会创建一个局部变量,该变量会隐藏同名的全局变量。当func1()返回时,本地超出范围并被垃圾收集;同时,func2()除了(未修改的)全局名称之外永远不会看到任何其他内容。请注意,此命名空间决定发生在编译时,而不是在运行时 - 如果您在分配给它之前在func1()中读取myGlobal的值,则会得到UnboundLocalError ,因为Python已经决定它必须是一个局部变量,但它还没有任何与之相关的值。但是通过使用global语句,你告诉Python应该在其他地方查找名称而不是在本地分配。[54]


(我相信这种行为很大程度上是由于本地命名空间的优化 - 没有这种行为,Python的VM每次在函数内部分配新名称时都需要执行至少三次名称查找(以确保名称)并没有在模块/内置级别存在,这将显着减慢非常常见的操作。)

其它参考2


您可能想要探索命名空间的概念。在Python中,模块是全局数据的自然位置:[55] [56]



  每个模块都有自己的私有符号表,该表用作模块中定义的所有函数的全局符号表。因此,模块的作者可以在模块中使用全局变量,而不必担心与用户的全局变量的意外冲突。另一方面,如果您知道自己在做什么,可以使用与其函数相同的符号来触摸模块的全局变量,modname.itemname



这里描述了模块中全局模块的特定用法 - 如何在模块间共享全局变量,并且为了完整性,内容在此处共享:[57]



  在单个程序中跨模块共享信息的规范方法是创建一个特殊的配置模块(通常称为config或cfg)。只需在应用程序的所有模块中导入配置模块;然后该模块可用作全局名称。因为每个模块只有一个实例,所以对模块对象所做的任何更改都会在任何地方反映出来。例如:

  
  文件:config.py



x = 0   # Default value of the 'x' configuration setting



  文件:mod.py



import config
config.x = 1



  文件:main.py



import config
import mod
print config.x

其它参考3


Python使用一个简单的启发式方法来决定它应该在本地和全局之间加载变量的范围。如果变量名称出现在赋值的左侧,但未声明为全局变量,则假定它是本地的。如果它没有出现在作业的左侧,则假定它是全局的。


>>> import dis
>>> def foo():
...     global bar
...     baz = 5
...     print bar
...     print baz
...     print quux
... 
>>> dis.disassemble(foo.func_code)
  3           0 LOAD_CONST               1 (5)
              3 STORE_FAST               0 (baz)

  4           6 LOAD_GLOBAL              0 (bar)
              9 PRINT_ITEM          
             10 PRINT_NEWLINE       

  5          11 LOAD_FAST                0 (baz)
             14 PRINT_ITEM          
             15 PRINT_NEWLINE       

  6          16 LOAD_GLOBAL              1 (quux)
             19 PRINT_ITEM          
             20 PRINT_NEWLINE       
             21 LOAD_CONST               0 (None)
             24 RETURN_VALUE        
>>> 


看看foo()中赋值左侧出现的baz是唯一的LOAD_FAST变量。

其它参考4


如果要在函数中引用全局变量,可以使用全局关键字来声明哪些变量是全局变量。你不必在所有情况下都使用它(正如这里有人错误地声称的那样) - 如果表达式中引用的名称在本地范围或定义此函数的函数中的作用域中找不到,则在全局范围内查找变量。


但是,如果分配给函数中未声明为全局的新变量,则它将隐式声明为local,并且它可以掩盖具有相同名称的任何现有全局变量。


此外,全局变量是有用的,与一些声称不同的OOP狂热者相反 - 特别是对于较小的脚本,其中OOP是过度的。

其它参考5


除了已经存在的答案,并使这更令人困惑:



  在Python中,仅在函数内引用的变量是
  隐式全球。如果在任何地方为变量分配了新值
  在函数体内,它被假定为本地。如果是变量
  在函数内部分配了一个新值,变量是
  隐式本地,您需要明确地将其声明为全局。

  
  虽然起初有点令人惊讶,但片刻的考虑解释了
  这个。一方面,要求全局分配变量提供了一个
  禁止意外的副作用。另一方面,如果全球化了
  所有全局引用都需要,你将全局使用全局
  时间。您必须声明为内置的每个引用的全局
  功能或导入模块的组件。这种混乱会
  挫败全球宣言的有用性
  副作用。



来源: Python中局部变量和全局变量的规则是什么?。[58]

其它参考6



  

如果我在一个函数中创建一个全局变量,我该如何在另一个函数中使用该变量?




我们可以使用以下函数创建一个全局:


def create_global_variable():
    global global_variable # must declare it to be a global first
    # modifications are thus reflected on the module's global scope
    global_variable = 'Foo' 


编写函数实际上并不运行其代码。所以我们称之为create_global_variable函数:


>>> create_global_variable()


使用不修改的全局变量



您可以使用它,只要您不希望更改它指向的对象:


例如,


def use_global_variable():
    return global_variable + '!!!'


现在我们可以使用全局变量:


>>> use_global_variable()
'Foo!!!'


从函数内部修改全局变量



要将全局变量指向其他对象,您需要再次使用global关键字:


def change_global_variable():
    global global_variable
    global_variable = 'Bar'


请注意,在编写此函数后,实际更改它的代码仍未运行:


>>> use_global_variable()
'Foo!!!'


所以在调用函数后:


>>> change_global_variable()


我们可以看到全局变量已经改变。 global_variable名称现在指向'Bar':


>>> use_global_variable()
'Bar!!!'


请注意,Python中的全局并不是真正的全局 - 它只是模块级别的全局。所以它只适用于在全局模块中编写的函数。函数会记住它们编写的模块,所以当它们被导出到其他模块时,它们仍会查看创建它们的模块以查找全局变量。


具有相同名称的本地变量



如果您创建一个具有相同名称的局部变量,它将掩盖一个全局变量:


def use_local_with_same_name_as_global():
    # bad name for a local variable, though.
    global_variable = 'Baz' 
    return global_variable + '!!!'

>>> use_local_with_same_name_as_global()
'Baz!!!'


但是使用那个错误命名的局部变量不会改变全局变量:


>>> use_global_variable()
'Bar!!!'


请注意,除非您确切知道自己在做什么并且有充分的理由这样做,否则应该避免使用与globals同名的局部变量。我还没有遇到过这样的道理。

其它参考7


使用并行执行时,如果您不了解发生的情况,全局变量可能会导致意外结果。以下是在多处理中使用全局变量的示例。我们可以清楚地看到每个进程都使用自己的变量副本:


import multiprocessing
import os
import random
import sys
import time

def worker(new_value):
    old_value = get_value()
    set_value(random.randint(1, 99))
    print('pid=[{pid}] '
          'old_value=[{old_value:2}] '
          'new_value=[{new_value:2}] '
          'get_value=[{get_value:2}]'.format(
          pid=str(os.getpid()),
          old_value=old_value,
          new_value=new_value,
          get_value=get_value()))

def get_value():
    global global_variable
    return global_variable

def set_value(new_value):
    global global_variable
    global_variable = new_value

global_variable = -1

print('before set_value(), get_value() = [%s]' % get_value())
set_value(new_value=-2)
print('after  set_value(), get_value() = [%s]' % get_value())

processPool = multiprocessing.Pool(processes=5)
processPool.map(func=worker, iterable=range(15))


输出:


before set_value(), get_value() = [-1]
after  set_value(), get_value() = [-2]
pid=[53970] old_value=[-2] new_value=[ 0] get_value=[23]
pid=[53971] old_value=[-2] new_value=[ 1] get_value=[42]
pid=[53970] old_value=[23] new_value=[ 4] get_value=[50]
pid=[53970] old_value=[50] new_value=[ 6] get_value=[14]
pid=[53971] old_value=[42] new_value=[ 5] get_value=[31]
pid=[53972] old_value=[-2] new_value=[ 2] get_value=[44]
pid=[53973] old_value=[-2] new_value=[ 3] get_value=[94]
pid=[53970] old_value=[14] new_value=[ 7] get_value=[21]
pid=[53971] old_value=[31] new_value=[ 8] get_value=[34]
pid=[53972] old_value=[44] new_value=[ 9] get_value=[59]
pid=[53973] old_value=[94] new_value=[10] get_value=[87]
pid=[53970] old_value=[21] new_value=[11] get_value=[21]
pid=[53971] old_value=[34] new_value=[12] get_value=[82]
pid=[53972] old_value=[59] new_value=[13] get_value=[ 4]
pid=[53973] old_value=[87] new_value=[14] get_value=[70]

其它参考8


您需要在要使用的每个函数中引用全局变量。


如下:


var = "test"

def printGlobalText():
    global var #wWe are telling to explicitly use the global version
    var = "global from printGlobalText fun."
    print "var from printGlobalText: " + var

def printLocalText():
    #We are NOT telling to explicitly use the global version, so we are creating a local variable
    var = "local version from printLocalText fun"
    print "var from printLocalText: " + var

printGlobalText()
printLocalText()
"""
Output Result:
var from printGlobalText: global from printGlobalText fun.
var from printLocalText: local version from printLocalText
[Finished in 0.1s]
"""

其它参考9


你要说的是使用这样的方法:


globvar = 5

def f():
    var = globvar
    print(var)

f()  # Prints 5


但更好的方法是使用这样的全局变量:


globavar = 5
def f():
    global globvar
    print(globvar)
f()   #prints 5


两者都给出相同的输出。

其它参考10


你实际上并没有将全局存储在局部变量中,只是创建了对原始全局引用所引用的同一对象的本地引用。请记住,Python中的所有内容都是引用对象的名称,并且没有任何内容被复制到平常的操作。


如果您没有必要明确指定标识符何时引用预定义的全局,那么您可能必须明确指定标识符何时是新的局部变量(例如,使用类似var命令的内容)在JavaScript中看到)。由于局部变量在任何严重且非平凡的系统中比全局变量更常见,因此Python的系统在大多数情况下更有意义。


可能有一种试图猜测的语言,如果它存在则使用全局变量或者如果它没有那么创建局部变量。但是,这将非常容易出错。例如,导入另一个模块可能会无意中通过该名称引入全局变量,从而改变程序的行为。

其它参考11


事实证明,答案总是很简单。


这是一个小样本模块。它是一种在主要定义中显示它的方法:


def five(enterAnumber,sumation):
    global helper
    helper  = enterAnumber + sumation

def isTheNumber():
    return helper


这是一种在主要定义中显示它的方法:


import TestPy

def main():
    atest  = TestPy
    atest.five(5,8)
    print(atest.isTheNumber())

if __name__ == '__main__':
    main()


这个简单的代码就像这样,它将执行。我希望它有所帮助。

其它参考12


尝试这个:


def x1():
    global x
    x = 6

def x2():
    global x
    x = x+1
    print x

x = 5
x1()
x2()  # output --> 7

其它参考13


接下来,作为一个补充,使用一个文件来包含所有在本地声明的全局变量,然后import as:


文件initval.py



Stocksin = 300
Prices = []


档案getstocks.py



import  initval as  iv

Def   getmystocks (): 
     iv.Stocksin  = getstockcount ()


Def getmycharts ():
    For ic in range (0,iv.Stocksin):


.....

其它参考14


写入全局数组的显式元素显然不需要全局声明,尽管写入批发确实有这样的要求:


import numpy as np

hostValue = 3.14159
hostArray = np.array([2., 3.])
hostMatrix = np.array([**1.0, 0.0],[ 0.0, 1.0**])

def func1():
    global hostValue    # mandatory, else local.
    hostValue = 2.0

def func2():
    global hostValue    # mandatory, else UnboundLocalError.
    hostValue += 1.0

def func3():
    global hostArray    # mandatory, else local.
    hostArray = np.array([14., 15.])

def func4():            # no need for globals
    hostArray[0] = 123.4

def func5():            # no need for globals
    hostArray[1] += 1.0

def func6():            # no need for globals
    hostMatrix[1][1] = 12.

def func7():            # no need for globals
    hostMatrix[0][0] += 0.33

func1()
print "After func1(), hostValue = ", hostValue
func2()
print "After func2(), hostValue = ", hostValue
func3()
print "After func3(), hostArray = ", hostArray
func4()
print "After func4(), hostArray = ", hostArray
func5()
print "After func5(), hostArray = ", hostArray
func6()
print "After func6(), hostMatrix = \n", hostMatrix
func7()
print "After func7(), hostMatrix = \n", hostMatrix

其它参考15


如果您有一个具有相同名称的局部变量,您可能想要使用globals()函数。[59]


globals()['your_global_var'] = 42

其它参考16


引用要在其中显示更改的类命名空间。


在此示例中,runner正在使用文件配置中的 max 。我想让我的测试在跑步者使用时改变 max 的值。


主/config.py


max = 15000


主/runner.py


from main import config
def check_threads():
    return max < thread_count 


测试/runner_test.py


from main import runner                # <----- 1. add file
from main.runner import check_threads
class RunnerTest(unittest):
   def test_threads(self):
       runner.max = 0                  # <----- 2. set global 
       check_threads()

其它参考17


我添加这个,因为我没有在任何其他答案中看到它,这对于那些在类似的事情上挣扎的人来说可能是有用的。 globals()函数返回一个可变的全局符号字典,您可以神奇地为其余代码提供数据。
例如:


from pickle import load
def loaditem(name):
    with open(r"C:\pickle\file\location"+"\{}.dat".format(name), "rb") as openfile:
        globals()[name] = load(openfile)
    return True





from pickle import dump
def dumpfile(name):
    with open(name+".dat", "wb") as outfile:
        dump(globals()[name], outfile)
    return True


只允许您将变量转储/加载到全局命名空间中。超级方便,没有麻烦,没有大惊小怪。很确定它只是python 3。