python:在函数中使用全局变量

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

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


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

1
2
3
4
5
6
7
8
9
10
11
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关键字来确保您确实知道这就是您要处理的内容。

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


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

假设你有这样一个模块:

1
2
3
4
5
6
7
8
9
10
11
# sample.py
myGlobal = 5

def func1():
    myGlobal = 42

def func2():
    print myGlobal

func1()
func2()

您可能期望这个输出42,但实际上它输出了5。如前所述,如果您将"global"声明添加到func1(),则func2()将打印42。

1
2
3
def func1():
    global myGlobal
    myGlobal = 42

这里的情况是,Python假设,任何一个函数内的任何地方的名称,都是该函数的局部名称,除非明确地告诉它不是这样的。如果它只是从一个名称中读取,而该名称在本地不存在,它将尝试在任何包含范围(例如模块的全局范围)中查找该名称。

因此,当您将42赋值给名称myGlobal时,Python将创建一个局部变量,该变量对同名的全局变量进行阴影处理。该局部超出范围,并在func1()返回时被垃圾收集;同时,func2()只能看到(未修改的)全局名。注意,这个名称空间决策发生在编译时,不是在运行时,如果你要读myGlobalfunc1()的值分配给它之前,你会得到一个UnboundLocalError,因为Python已经决定,它必须是一个局部变量,但还没有与之关联的值。但是,通过使用"global"语句,您可以告诉Python,它应该在其他地方查找名称,而不是在本地分配名称。

(我认为这种行为是主要通过一个优化的本地名称空间——没有这种行为,Python的VM需要执行每次至少有三个名称查找一个新名字是分配给内部函数(确保名称不存在的模块/内装式水平),这将显著降低很常见的操作。)


您可能想探究名称空间的概念。在Python中,模块是全局数据的自然位置:

Each module has its own private symbol table, which is used as the global symbol table by all functions defined in the module. Thus, the author of a module can use global variables in the module without worrying about accidental clashes with a user’s global variables. On the other hand, if you know what you are doing you can touch a module’s global variables with the same notation used to refer to its functions, modname.itemname.

这里描述了模块中的全局变量的一个特殊用法——how-do-i-share-全局变量- cross-modules,为了完整起见,内容在这里共享:

The canonical way to share information across modules within a single program is to create a special configuration module (often called config or cfg). Just import the configuration module in all modules of your application; the module then becomes available as a global name. Because there is only one instance of each module, any changes made to the module object get reflected everywhere. For example:

File: config.py

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

File: mod.py

1
2
import config
config.x = 1

File: main.py

1
2
3
import config
import mod
print config.x


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
>>> 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变量的。


如果希望在函数中引用全局变量,可以使用global关键字声明哪些变量是全局变量。您不需要在所有情况下都使用它(这里有人错误地声称)——如果表达式中引用的名称不能在局部作用域中找到,或者不能在定义该函数的函数的作用域中找到,那么就在全局变量中查找它。

但是,如果您在函数中为一个没有声明为全局的新变量赋值,那么它将隐式地声明为局部变量,并且它可以遮蔽任何具有相同名称的现有全局变量。

此外,全局变量也很有用,这与一些OOP狂热者的说法相反,他们不这么认为——尤其是对于较小的脚本,OOP是一种过度使用的脚本。


除了已经存在的答案,更让人困惑的是:

In Python, variables that are only referenced inside a function are
implicitly global. If a variable is assigned a new value anywhere
within the function’s body, it’s assumed to be a local. If a variable
is ever assigned a new value inside the function, the variable is
implicitly local, and you need to explicitly declare it as ‘global’.

Though a bit surprising at first, a moment’s consideration explains
this. On one hand, requiring global for assigned variables provides a
bar against unintended side-effects. On the other hand, if global was
required for all global references, you’d be using global all the
time. You’d have to declare as global every reference to a built-in
function or to a component of an imported module. This clutter would
defeat the usefulness of the global declaration for identifying
side-effects.

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


If I create a global variable in one function, how can I use that variable in another function?

我们可以创建一个全局的功能如下:

1
2
3
4
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函数:

1
>>> create_global_variable()

使用未修改的全局变量

你可以直接使用它,只要你不想改变它指向的对象:

例如,

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

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

1
2
>>> use_global_variable()
'Foo!!!'

从函数内部修改全局变量

要将全局变量指向另一个对象,需要再次使用全局关键字:

1
2
3
def change_global_variable():
    global global_variable
    global_variable = 'Bar'

注意,在编写这个函数之后,实际修改它的代码仍然没有运行:

1
2
>>> use_global_variable()
'Foo!!!'

调用函数后:

1
>>> change_global_variable()

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

1
2
>>> use_global_variable()
'Bar!!!'

注意,Python中的"全局"并不是真正的全局——它只是模块级别的全局。因此,它只对在其中是全局的模块中编写的函数可用。函数记住它们是在哪个模块中编写的,因此当它们被导出到其他模块时,它们仍然会在创建它们的模块中查找全局变量。

同名局部变量

如果你创建一个同名的局部变量,它会遮蔽全局变量:

1
2
3
4
5
6
7
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!!!'

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

1
2
>>> use_global_variable()
'Bar!!!'

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


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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))

输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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]

你的意思是这样使用方法:

1
2
3
4
5
6
7
globvar = 5

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

f()  # Prints 5

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

1
2
3
4
5
globavar = 5
def f():
    global globvar
    print(globvar)
f()   #prints 5

两者都给出相同的输出。


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

下面是一个小的示例模块,用简单的方法在main定义中显示它:

1
2
3
4
5
6
def five(enterAnumber,sumation):
    global helper
    helper  = enterAnumber + sumation

def isTheNumber():
    return helper

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

1
2
3
4
5
6
7
8
9
import TestPy

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

if __name__ == '__main__':
    main()

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


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

如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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]
"""


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

如果您不需要显式地指定标识符何时引用预定义的全局变量,那么您可能需要显式地指定标识符何时是新的本地变量(例如,使用JavaScript中类似"var"的命令)。由于在任何严肃和重要的系统中,局部变量比全局变量更常见,所以Python的系统在大多数情况下更有意义。

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


试试这个:

1
2
3
4
5
6
7
8
9
10
11
12
def x1():
    global x
    x = 6

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

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

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

文件initval.py

1
2
Stocksin = 300
Prices = []

文件getstocks.py

1
2
3
4
5
6
7
8
import  initval as  iv

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


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

.....


写入一个全局数组的显式元素显然不需要全局声明,但是写入它的"批发"确实有这个要求:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
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 =
"
, hostMatrix
func7()
print"After func7(), hostMatrix =
"
, hostMatrix

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

1
globals()['your_global_var'] = 42


我加上这个,因为我没有在任何其他答案中看到它,它可能是有用的人与类似的东西斗争。函数的作用是:返回一个可变的全局符号字典,在这个字典中,您可以"神奇地"将数据提供给代码的其余部分。例如:

1
2
3
4
5
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

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

它只允许您将变量转储/加载到全局名称空间中。超级方便,没有混乱,没有大惊小怪。很确定只有python3。


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

在本例中,runner使用文件配置中的max。我想让我的测试在runner使用max时改变它的值。

主要/ config.py

1
max = 15000

主要/ runner.py

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

测试/ runner_test.py

1
2
3
4
5
6
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()