如何在函数中创建或使用全局变量?
如果我在一个函数中创建一个全局变量,如何在另一个函数中使用该全局变量?我是否需要将全局变量存储在需要访问的函数的局部变量中?
如何在函数中创建或使用全局变量?
如果我在一个函数中创建一个全局变量,如何在另一个函数中使用该全局变量?我是否需要将全局变量存储在需要访问的函数的局部变量中?
您可以在其他函数中使用全局变量,方法是将其声明为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
由于不清楚globvar = 1
是创建局部变量还是更改全局变量,Python 默认创建局部变量,并让您使用global
关键字显式选择其他行为。
如果您想跨模块共享全局变量,请参阅其他答案。
如果我正确理解您的情况,那么您所看到的是 Python 如何处理本地(函数)和全局(模块)命名空间的结果。
假设你有一个这样的模块:
# sample.py
myGlobal = 5
def func1():
myGlobal = 42
def func2():
print myGlobal
func1()
func2()
您可能希望这会打印 42,但实际上它会打印 5。正如已经提到的,如果您向 中添加 ' global
' 声明func1()
,func2()
则将打印 42。
def func1():
global myGlobal
myGlobal = 42
这里发生的事情是,Python 假定分配给的任何名称,在函数内的任何位置,都是该函数的本地名称,除非另有明确说明。如果它只是从一个名称中读取,并且该名称在本地不存在,它将尝试在任何包含范围(例如模块的全局范围)中查找该名称。
因此,当您将 42 分配给 namemyGlobal
时,Python 会创建一个局部变量来隐藏同名的全局变量。该本地超出范围并在返回时被垃圾收集;func1()
同时,func2()
除了(未修改的)全局名称之外,永远看不到任何东西。请注意,这个命名空间决定发生在编译时,而不是运行时——如果你在分配给它之前读取myGlobal
inside的值func1()
,你会得到一个UnboundLocalError
,因为 Python 已经决定它必须是一个局部变量,但是它还没有任何与之相关的价值。但是通过使用 ' global
' 语句,您告诉 Python 它应该在别处寻找名称,而不是在本地分配给它。
(我相信这种行为主要源于对本地命名空间的优化——如果没有这种行为,Python 的 VM 将需要在每次将新名称分配给函数内部时执行至少三个名称查找(以确保名称没有t 已经存在于模块/内置级别),这将显着减慢非常常见的操作。)
您可能想探索命名空间的概念。在 Python 中,模块是存放全局数据的天然场所:
每个模块都有自己的私有符号表,它被模块中定义的所有函数用作全局符号表。因此,模块的作者可以在模块中使用全局变量,而不必担心与用户的全局变量发生意外冲突。另一方面,如果您知道自己在做什么,则可以使用与引用其函数相同的符号来触摸模块的全局变量,
modname.itemname
.
此处描述了 global-in-a-module 的特定用法-如何跨模块共享全局变量?,为了完整起见,这里共享内容:
在单个程序中跨模块共享信息的规范方法是创建一个特殊的配置模块(通常称为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
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
>>>
看看出现在赋值左侧的 baz 如何foo()
是唯一的LOAD_FAST
变量。
如果要在函数中引用全局变量,可以使用global关键字来声明哪些变量是全局的。您不必在所有情况下都使用它(正如这里有人错误地声称的那样) - 如果在定义此函数的函数的本地范围或范围内找不到表达式中引用的名称,则在全局范围内查找它变量。
但是,如果您分配给未在函数中声明为全局的新变量,它会被隐式声明为局部,并且它可以覆盖任何现有的同名全局变量。
此外,全局变量很有用,这与一些 OOP 狂热者声称的相反——尤其是对于较小的脚本,因为 OOP 是多余的。
如果我在一个函数中创建一个全局变量,如何在另一个函数中使用该变量?
我们可以使用以下函数创建一个全局变量:
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!!!'
请注意,您应该避免使用与全局变量同名的局部变量,除非您确切地知道自己在做什么并且有充分的理由这样做。我还没有遇到过这样的原因。
后续评论询问:
如果我想在一个类的函数内创建一个全局变量,并想在另一个类的另一个函数内使用该变量,该怎么办?
在这里,我演示了我们在方法中获得与在常规函数中相同的行为:
class Foo:
def foo(self):
global global_variable
global_variable = 'Foo'
class Bar:
def bar(self):
return global_variable + '!!!'
Foo().foo()
现在:
>>> Bar().bar()
'Foo!!!'
但我建议不要使用全局变量,而是使用类属性,以避免混淆模块命名空间。另请注意,我们在这里不使用self
参数 - 这些可能是类方法(如果从通常的cls
参数中改变类属性,则很方便)或静态方法(noself
或cls
)。
除了已经存在的答案并使这更加混乱:
在 Python 中,仅在函数内部引用的变量是 隐式全局的。如果一个变量在函数体中的任何地方都被赋予了一个新值,那么它被假定为一个local。如果一个变量在函数内部被赋予了一个新值,那么该变量是隐式本地的,您需要将其显式声明为“全局”。
虽然起初有点令人惊讶,但片刻的考虑解释了这一点。一方面,对已分配的变量要求全局性提供了防止意外副作用的障碍。另一方面,如果所有全局引用都需要全局,那么您将一直使用全局。您必须将对内置函数或导入模块组件的每个引用声明为全局。这种混乱会破坏全局声明识别副作用的有用性。
资料来源:Python中局部变量和全局变量的规则是什么?.
通过并行执行,如果您不了解正在发生的事情,全局变量可能会导致意外结果。这是在多处理中使用全局变量的示例。我们可以清楚地看到每个进程都使用自己的变量副本:
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]
事实证明,答案总是很简单。
这是一个小示例模块,它以一种简单的方式在main
定义中显示:
def five(enterAnumber,sumation):
global helper
helper = enterAnumber + sumation
def isTheNumber():
return helper
以下是如何在main
定义中显示它:
import TestPy
def main():
atest = TestPy
atest.five(5,8)
print(atest.isTheNumber())
if __name__ == '__main__':
main()
这个简单的代码就是这样工作的,它会执行。我希望它有所帮助。
你说的是使用这样的方法:
globvar = 5
def f():
var = globvar
print(var)
f() # Prints 5
但更好的方法是像这样使用全局变量:
globvar = 5
def f():
global globvar
print(globvar)
f() #prints 5
两者都给出相同的输出。
您需要在要使用的每个函数中引用全局变量。
如下:
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]
"""
试试这个:
def x1():
global x
x += 1
print('x1: ', x)
def x2():
global x
x = x+1
print('x2: ', x)
x = 5
print('x: ', x)
x1()
x2()
# Output:
# x: 5
# x1: 6
# x2: 7
您实际上并没有将全局存储在局部变量中,只是创建对原始全局引用所引用的同一对象的局部引用。请记住,Python 中的几乎所有内容都是引用对象的名称,在通常的操作中不会复制任何内容。
如果您不必显式指定标识符何时引用预定义的全局变量,那么您可能必须显式指定标识符何时是新的局部变量(例如,使用类似 'var' 命令见于 JavaScript)。由于在任何严肃和重要的系统中,局部变量比全局变量更常见,因此 Python 的系统在大多数情况下更有意义。
您可以使用一种尝试猜测的语言,如果存在则使用全局变量,如果不存在则创建局部变量。但是,这将非常容易出错。例如,导入另一个模块可能会无意中引入该名称的全局变量,从而改变程序的行为。
如果您有一个同名的局部变量,您可能需要使用该globals()
函数。
globals()['your_global_var'] = 42
接下来并作为附加组件,使用一个文件来包含所有在本地声明的全局变量,然后import as
:
文件initval.py:
Stocksin = 300
Prices = []
文件getstocks.py:
import initval as iv
def getmystocks():
iv.Stocksin = getstockcount()
def getmycharts():
for ic in range(iv.Stocksin):
写入全局数组的显式元素显然不需要全局声明,尽管写入“批发”确实有这个要求:
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
我正在添加这个,因为我在其他任何答案中都没有看到它,它可能对那些在类似问题上苦苦挣扎的人有用。该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。
引用要显示更改的类名称空间。
在此示例中,runner 使用文件配置中的max。我希望我的测试在跑步者使用它时改变max的值。
主/config.py
max = 15000
主/亚军.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()
与不同平台/环境上的多处理相关的全局变量,一方面是 Windows/Mac OS,另一方面是 Linux,这很麻烦。
我将通过一个简单的示例向您展示这一点,指出我前段时间遇到的一个问题。
如果您想了解,为什么 Windows/MacO 和 Linux 上的情况有所不同,您需要知道,启动新进程的默认机制...
它们在内存分配和初始化方面是不同的......(但我在这里不讨论)。
让我们看一下问题/示例...
import multiprocessing
counter = 0
def do(task_id):
global counter
counter +=1
print(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 上运行它(我想也在 MacOS 上),你会得到以下输出......
task 0: counter = 1
task 1: counter = 2
task 2: counter = 3
task 3: counter = 4
如果你在 Linux 上运行它,你会得到以下结果。
task 0: counter = 1
task 1: counter = 1
task 2: counter = 1
task 3: counter = 1
有两种方法可以将变量声明为全局变量:
1.在函数内部分配变量并使用全局行
def declare_a_global_variable():
global global_variable_1
global_variable_1 = 1
# Note to use the function to global variables
declare_a_global_variable()
2. 分配变量外部函数:
global_variable_2 = 2
现在我们可以在其他函数中使用这些声明的全局变量:
def declare_a_global_variable():
global global_variable_1
global_variable_1 = 1
# Note to use the function to global variables
declare_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 = 1
global_variable_2 = 2
def update_variables():
global global_variable_1
global_variable_1 = 11
global_variable_2 = 12 # will update just locally for this function
update_variables()
print(global_variable_1) # prints 11
print(global_variable_2) # prints 2
笔记2:
列表和字典变量的注释 1 有一个例外,但在函数内不使用全局行:
# declaring some global variables
variable = '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 scope
list_variable_1 = ['A','B'] # won't update in global scope
list_variable_2[0] = 'C' # updated in global scope surprisingly this way
list_variable_2[1] = 'D' # updated in global scope surprisingly this way
update_global_variables()
print('variable is: %s'%variable) # prints peter
print('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=20
globals()['y']=50
someFunc() # invoking function so that variable Y is created globally
print(y) # output 50
print(x) #NameError: name 'x' is not defined as x was defined locally within function
像这样的代码:
myVar = 12
def myFunc():
myVar += 12
钥匙:
如果你在字符串之外声明一个变量,它就会变成全局变量。
如果你在字符串中声明一个变量,它就会变成本地的。
如果要在字符串中声明全局变量,请在要声明的变量global
之前使用关键字:
myVar = 124
def myFunc():
global myVar2
myVar2 = 100
myFunc()
print(myVar2)
然后文档中有 100 个。