在函数中使用全局变量

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

如何在其他函数中使用在一个函数中定义的全局变量?


未能在适当的地方使用global关键字通常会导致UnboundLocalError。这方面的确切规则在首次使用后重新分配时局部变量上的无边界位置错误中解释

3851872 次浏览

您可能想探索命名空间的概念。在Python中,模块全球数据的自然位置:

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

这里描述了全局模块的具体用法-如何跨模块共享全局变量?,为了完整起见,内容在这里共享:

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

文件:config.py

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

文件:mod.py

import configconfig.x = 1

文件:main.py

import configimport modprint config.x

您可以在其他函数中使用全局变量,方法是在为其赋值的每个函数中将其声明为global

globvar = 0
def set_globvar_to_one():global globvar    # Needed to modify global copy of globvarglobvar = 1
def print_globvar():print(globvar)     # No need for global declaration to read value of globvar
set_globvar_to_one()print_globvar()       # Prints 1

由于不清楚globvar = 1是创建局部变量还是更改全局变量,Python默认创建局部变量,并让您使用global关键字显式选择其他行为。

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

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

但是,如果您分配给一个未在函数中声明为全局的新变量,它将被隐式声明为本地变量,并且它可以覆盖任何具有相同名称的现有全局变量。

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

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

假设你有一个这样的模块:

# sample.py_my_global = 5
def func1():_my_global = 42
def func2():print _my_global
func1()func2()

您可能期望它打印42,但它打印5。如前所述,如果您在func1()中添加“global”声明,那么func2()将打印42。

def func1():global _my_global_my_global = 42

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

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

(我相信这种行为很大程度上源于对本地命名空间的优化——如果没有这种行为,Python的虚拟机每次在函数内部分配新名称时都需要执行至少三次名称查找(以确保名称在模块/内置级别不存在),这会显着减慢一个非常常见的操作。

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

如果你不必显式指定标识符何时引用预定义的全局变量,那么你大概必须显式指定标识符何时是新的局部变量(例如,使用JavaScript中的“var”命令)。由于局部变量在任何严肃和重要的系统中比全局变量更常见,因此Python的系统在大多数情况下更有意义。

可以有一种试图猜测的语言,如果存在则使用全局变量,如果不存在则创建局部变量。然而,这将非常容易出错。例如,导入另一个模块可能会无意中引入一个同名的全局变量,从而改变程序的行为。

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_ITEM10 PRINT_NEWLINE
5          11 LOAD_FAST                0 (baz)14 PRINT_ITEM15 PRINT_NEWLINE
6          16 LOAD_GLOBAL              1 (quux)19 PRINT_ITEM20 PRINT_NEWLINE21 LOAD_CONST               0 (None)24 RETURN_VALUE>>>

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

在并行执行时,如果你不明白发生了什么,全局变量可能会导致意想不到的结果。这是一个在多重处理中使用全局变量的例子。我们可以清楚地看到每个进程都使用自己的变量副本:

import multiprocessingimport osimport randomimport sysimport 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_variablereturn global_variable
def set_value(new_value):global global_variableglobal_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]

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

这是一个小示例模块,用一种简单的方法将其显示在main定义中:

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

以下是如何在main定义中显示它:

import TestPy
def main():atest  = TestPyatest.five(5,8)print(atest.isTheNumber())
if __name__ == '__main__':main()

这段简单的代码就是这样工作的,它会执行。我希望它有帮助。

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

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

虽然一开始有点惊讶,但片刻的思考解释了这。一方面,要求全局分配变量提供了一个禁止意外的副作用。另一方面,如果全局是对于所有全局引用,您将使用所有全局引用时间。您必须将对内置的每个引用声明为全局函数或导入模块的组件。这种混乱会挫败全球宣言的有用性副作用

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

你说的是这样使用方法:

globvar = 5
def f():var = globvarprint(var)
f()  # Prints 5

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

globvar = 5def f():global globvarprint(globvar)f()   #prints 5

两者都有相同的输出。

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

具体如下:

var = "test"
def printGlobalText():global var #wWe are telling to explicitly use the global versionvar = "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 variablevar = "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]"""

试试这个:

def x1():global xx += 1print('x1: ', x)
def x2():global xx = x+1print('x2: ', x)
x = 5print('x:  ', x)x1()x2()
# Output:# x:   5# x1:  6# x2:  7

作为附加组件,使用一个文件来包含所有全局变量,所有变量都在本地声明,然后import as

文件initval.py

Stocksin = 300Prices = []

文件getstocks.py

import initval as iv
def getmystocks():iv.Stocksin = getstockcount()

def getmycharts():for ic in range(iv.Stocksin):

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

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

def create_global_variable():global global_variable # must declare it to be a global first# modifications are thus reflected on the module's global scopeglobal_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_variableglobal_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!!!'

请注意,您应该避免使用与全局变量同名的局部变量,除非您确切地知道您在做什么并且有很好的理由这样做。我还没有遇到这样的原因。

我们在课堂上也有同样的行为

下面的评论问道:

如果我想在类中的函数中创建一个全局变量,并想在另一个类中的另一个函数中使用该变量,该怎么办?

在这里,我演示了我们在方法中获得与在常规函数中相同的行为:

class Foo:def foo(self):global global_variableglobal_variable = 'Foo'
class Bar:def bar(self):return global_variable + '!!!'
Foo().foo()

现在:

>>> Bar().bar()'Foo!!!'

但我建议不要使用全局变量,而是使用class属性,以避免模块命名空间混乱。还要注意,我们在这里不使用self参数-这些可以是类方法(如果从通常的cls参数更改class属性,则很方便)或静态方法(没有selfcls)。

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

import numpy as np
hostValue = 3.14159hostArray = 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 globalshostArray[0] = 123.4
def func5():            # no need for globalshostArray[1] += 1.0
def func6():            # no need for globalshostMatrix[1][1] = 12.
def func7():            # no need for globalshostMatrix[0][0] += 0.33
func1()print "After func1(), hostValue = ", hostValuefunc2()print "After func2(), hostValue = ", hostValuefunc3()print "After func3(), hostArray = ", hostArrayfunc4()print "After func4(), hostArray = ", hostArrayfunc5()print "After func5(), hostArray = ", hostArrayfunc6()print "After func6(), hostMatrix = \n", hostMatrixfunc7()print "After func7(), hostMatrix = \n", hostMatrix

如果您有同名的局部变量,您可能希望使用#0函数

globals()['your_global_var'] = 42

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

在此示例中,运行器使用文件配置中的最大值。我希望我的测试在运行器使用它时更改最大值的值。

主要/config.py

max = 15000

主要/runner.py

from main import configdef check_threads():return max < thread_count

测试/runner_test.py

from main import runner                # <----- 1. add filefrom main.runner import check_threadsclass RunnerTest(unittest):def test_threads(self):runner.max = 0                  # <----- 2. set globalcheck_threads()

我添加这个是因为我没有在任何其他答案中看到它,它可能对正在努力解决类似问题的人有用。#0函数返回一个可变的全局符号字典,您可以在其中“神奇地”使数据可用于其余代码。例如:

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

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

只会让你将变量转储/加载到全局命名空间中。超级方便,没有混乱,没有大惊小怪。很确定它只是Python 3。

全局都很好-除了多重处理

与不同平台/环境上的多重处理相关的全局因为Windows/Mac OS在一边,Linux在另一边很麻烦。

我将用一个简单的例子向您展示这一点,指出我前段时间遇到的一个问题。

如果您想了解为什么Windows/MacOS上的情况不同并Linux您需要知道的是,启动新进程的默认机制…

  • Windows/MacOS正在“生成”
  • Linux是“叉子”

它们在内存分配和初始化方面是不同的…(但我不深入讨论这个在这里)。

让我们来看看问题/例子…

import multiprocessing
counter = 0
def do(task_id):global countercounter +=1print(f'task {task_id}: counter = {counter}')
if __name__ == '__main__':
pool = multiprocessing.Pool(processes=4)task_ids = list(range(4))pool.map(do, task_ids)

windows

如果你在Windows上运行它(我想在MacOS上也是如此),你会得到以下输出…

task 0: counter = 1task 1: counter = 2task 2: counter = 3task 3: counter = 4

Linux

如果你在Linux上运行它,你会得到以下结果。

task 0: counter = 1task 1: counter = 1task 2: counter = 1task 3: counter = 1

有两种方法可以将变量声明为全局变量:

1.在函数内部分配变量并使用全局行

def declare_a_global_variable():global global_variable_1global_variable_1 = 1
# Note to use the function to global variablesdeclare_a_global_variable()

2.分配变量外部函数:

global_variable_2 = 2

现在我们可以在其他函数中使用这些声明的全局变量:

def declare_a_global_variable():global global_variable_1global_variable_1 = 1
# Note to use the function to global variablesdeclare_a_global_variable()global_variable_2 = 2
def print_variables():print(global_variable_1)print(global_variable_2)print_variables() # prints 1 & 2

注1:

如果你想在另一个函数(如update_variables())中更改全局变量,你应该在分配变量之前在该函数中使用全局行:

global_variable_1 = 1global_variable_2 = 2
def update_variables():global global_variable_1global_variable_1 = 11global_variable_2 = 12 # will update just locally for this function
update_variables()print(global_variable_1) # prints 11print(global_variable_2) # prints 2

注2:

注释1对于列表和字典变量有一个例外,同时在函数内不使用全局行:

# declaring some global variablesvariable = 'peter'list_variable_1 = ['a','b']list_variable_2 = ['c','d']
def update_global_variables():"""without using global line"""variable = 'PETER' # won't update in global scopelist_variable_1 = ['A','B'] # won't update in global scopelist_variable_2[0] = 'C' # updated in global scope surprisingly this waylist_variable_2[1] = 'D' # updated in global scope surprisingly this way
update_global_variables()
print('variable is: %s'%variable) # prints peterprint('list_variable_1 is: %s'%list_variable_1) # prints ['a', 'b']print('list_variable_2 is: %s'%list_variable_2) # prints ['C', 'D']

虽然这已经回答,我再次给出解决方案,因为我更喜欢单行这是如果你想在函数中创建全局变量

def someFunc():x=20globals()['y']=50someFunc() # invoking function so that variable Y is created globallyprint(y) # output 50print(x) #NameError: name 'x' is not defined as x was defined locally within function

像这样的代码:

myVar = 12
def myFunc():myVar += 12

关键:

如果您在字符串之外声明变量,它将成为全局变量。

如果您在字符串中声明变量,它将成为本地变量。

如果要在字符串中声明全局变量,请在要声明的变量之前使用关键字global

myVar = 124def myFunc():global myVar2myVar2 = 100myFunc()print(myVar2)

然后你在文档中有100个。

global_var = 10  # will be considered as a global variable

def func_1():global global_var  # access variable using variable keywordglobal_var += 1

def func_2():global global_varglobal_var *= 2print(f"func_2: {global_var}")

func_1()func_2()print("Global scope:", global_var) # will print 22

说明:

global_var是一个全局变量,所有函数和类都可以访问该变量。

func_1()使用关键字global访问该全局变量,该关键字指向写入全局范围的变量。如果我没有编写全局关键字,则func_1中的变量global_var被认为是仅在函数内部可用的局部变量。然后在func_1中,我将该全局变量增加了1。

同样的事情发生在func_2()

调用func_1func_2后,您将看到global_var发生了变化

Initialized = 0  #Here This Initialized is global variable
def Initialize():print("Initialized!")Initialized = 1  #This is local variable and assigning 1 to local variablewhile Initialized == 0:

这里我们比较全局变量初始化为0,所以循环条件为真

     Initialize()

函数将被调用。循环将是无限的

#if we do Initialized=1 then loop will terminate
else:print("Lets do something else now!")

如果你想访问全局变量,你只需在函数中添加全局关键字例如:global_var='是'

def someFunc():global global_var;print(nam_of_var)