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

2024-11-15 08:36:00
admin
原创
20
摘要:问题描述:如何在函数内部创建或使用全局变量?如何在其他函数中使用在一个函数中定义的全局变量?未能在适当的地方使用global关键字通常会导致UnboundLocalError。有关此问题的精确规则在UnboundLocalError on local variable when reassigned afte...

问题描述:

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

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


未能在适当的地方使用global关键字通常会导致UnboundLocalError。有关此问题的精确规则在UnboundLocalError on local variable when reassigned after first use中有说明。通常,当需要解释时,请关闭其他问题作为问题的重复,当有人只需要知道关键字时,请关闭global问题。


解决方案 1:

您可以在其它函数中使用全局变量,方法是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关键字明确选择其他行为。

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

解决方案 2:

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

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

# sample.py
_my_global = 5

def func1():
    _my_global = 42

def func2():
    print _my_global

func1()
func2()

您可能期望它打印 42,但实际上,它打印 5。如前所述,如果您向添加 ' global' 声明func1(),则将func2()打印 42。

def func1():
    global _my_global 
    _my_global = 42

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

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

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

解决方案 3:

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

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

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

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

文件: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

解决方案 4:

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        
>>> 

看看出现在赋值语句左侧的 bazfoo()是如何成为唯一LOAD_FAST变量的。

解决方案 5:

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

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

此外,全局变量很有用,这与一些 OOP 狂热分子的说法相反 - 特别是对于较小的脚本,因为 OOP 有点过度了。

解决方案 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!!!'

请注意,除非你清楚地知道自己在做什么,并且有充分的理由这样做,否则应避免使用与全局变量同名的局部变量。我还没有遇到过这样的情况。

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

后续评论问道:

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

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

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)或静态方法(无selfcls)。

解决方案 7:

除了已经存在的答案之外,还有一些更令人困惑的地方:

在 Python 中,仅在函数内部引用的变量是
隐式全局变量。如果在函数主体的任何地方为变量分配了新值,则假定该变量为局部变量。如果在函数内部为变量分配了新值,则该变量是隐式局部变量,您需要将其明确声明为“全局变量”。

虽然一开始有点令人惊讶,但稍加考虑就能解释这一点。一方面,要求分配的变量是全局变量可以防止意外的副作用。另一方面,如果所有全局引用都需要全局变量,那么您将一直使用全局变量。您必须将对内置函数或导入模块组件的每个引用声明为全局变量。这种混乱将使全局声明在识别副作用方面的实用性大打折扣。

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

解决方案 8:

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

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]

解决方案 9:

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

这是一个小的示例模块,其中以一种简单的方式在定义中显示它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()

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

解决方案 10:

你说的是用这样的方法:

globvar = 5

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

f()  # Prints 5

但更好的方法是使用全局变量,如下所示:

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

两者的输出相同。

解决方案 11:

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

具体如下:

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]
"""

解决方案 12:

尝试一下:

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

解决方案 13:

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

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

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

解决方案 14:

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

globals()['your_global_var'] = 42

解决方案 15:

接下来作为补充,使用一个文件包含所有在本地声明的全局变量,然后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):

解决方案 16:

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

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

解决方案 17:

global_var = 10  # will be considered as a global variable


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


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


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

解释:

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

使用指向全局范围内写入的变量的关键字访问该全局变量。如果我没有写全局关键字,则其中的变量被func_1()视为只能在函数内部使用的局部变量。然后在里面,我将该全局变量增加了 1。global`global_varfunc_1func_1`

同样的情况也发生在func_2()

调用func_1和后func_2,你会看到global_var发生了变化

解决方案 18:

我之所以添加这个,是因为我在其他答案中没有看到它,它可能对遇到类似问题的人有用。该globals()函数返回一个可变的全局符号字典,您可以在其中“神奇地”使数据可用于其余代码。例如:

from pickle import load
def loaditem(name):
    with open(r"C:pickleilelocation"+"{}.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。

解决方案 19:

引用您希望显示更改的类命名空间。

在此示例中,runner 使用文件配置中的max 。我希望我的测试在 runner 使用 max 时更改其值。

主要/配置.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()

解决方案 20:

全局变量很好 - 除了多处理

在不同平台/环境(比如一边是 Windows/Mac OS,另一边是 Linux)上进行多处理时,全局变量会比较麻烦。

我将通过一个简单的例子向您展示这一点,指出我之前遇到的一个问题。

如果您想了解为什么 Windows/MacOs 和 Linux 上的情况有所不同,您需要知道启动新进程的默认机制......

  • Windows/MacOs 是“spawn”

  • 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

如果你在 Linux 上运行此程序,你会看到以下内容。

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

解决方案 21:

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

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']

解决方案 22:

虽然这个问题已经得到解答,但我还是再次给出解决方案,因为我更喜欢单行这是如果你想在函数内创建全局变量

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

解决方案 23:

例如,在此代码中:

myVar = 12

def myFunc():
  myVar += 12

myVar是一个全局变量。

钥匙:

如果在括号外声明变量,该变量将成为全局变量(所有函数和其他括号都可以访问)。

如果在括号内声明一个变量,该变量将成为本地变量(只能在括号内访问)。

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

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

在这里,您将打印 100 份。

解决方案 24:

Initialized = 0  #Here This Initialized is global variable  

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

这里我们比较全局变量初始化为 0,因此 while 循环条件成立

     Initialize()

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

#if we do Initialized=1 then loop will terminate  

else:
    print("Lets do something else now!")

解决方案 25:

最大语法糖

我有一个相对简单的 Pythonic 解决方案,它透明地启用全局变量名的语法糖,就好像它们在你当前的模块中一样,即没有v.my_var必要,只需my_var。这对我很重要,因为我喜欢我的代码自我记录,我们的设计文档中有诸如“HT3 < 39”之类的公式,表示热水温度低于 39 摄氏度。

我这样做是为了使程序员的负担很小,甚至包含一个测试函数(你可以删除它)来证明它是有效的。

# main.py
from global_var import load_globals; load_globals(__name__, "variables")
from variables import *  # So that IDE removes squiggly underlines

# For test:
from modula_B import proof as proof1
from module_A import proof as proof2

H @ 103   # This is the new way of assigning, read "H at 101"
print("In main.py H =", H, id(H))

I = H + G
print("Result of H + G =", I)

# test:
proof1(H)
proof2(H)

# modula_B.py
相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   601  
  华为IPD与传统研发模式的8大差异在快速变化的商业环境中,产品研发模式的选择直接决定了企业的市场响应速度和竞争力。华为作为全球领先的通信技术解决方案供应商,其成功在很大程度上得益于对产品研发模式的持续创新。华为引入并深度定制的集成产品开发(IPD)体系,相较于传统的研发模式,展现出了显著的差异和优势。本文将详细探讨华为...
IPD流程是谁发明的   7  
  如何通过IPD流程缩短产品上市时间?在快速变化的市场环境中,产品上市时间成为企业竞争力的关键因素之一。集成产品开发(IPD, Integrated Product Development)作为一种先进的产品研发管理方法,通过其结构化的流程设计和跨部门协作机制,显著缩短了产品上市时间,提高了市场响应速度。本文将深入探讨如...
华为IPD流程   9  
  在项目管理领域,IPD(Integrated Product Development,集成产品开发)流程图是连接创意、设计与市场成功的桥梁。它不仅是一个视觉工具,更是一种战略思维方式的体现,帮助团队高效协同,确保产品按时、按质、按量推向市场。尽管IPD流程图可能初看之下显得错综复杂,但只需掌握几个关键点,你便能轻松驾驭...
IPD开发流程管理   8  
  在项目管理领域,集成产品开发(IPD)流程被视为提升产品上市速度、增强团队协作与创新能力的重要工具。然而,尽管IPD流程拥有诸多优势,其实施过程中仍可能遭遇多种挑战,导致项目失败。本文旨在深入探讨八个常见的IPD流程失败原因,并提出相应的解决方法,以帮助项目管理者规避风险,确保项目成功。缺乏明确的项目目标与战略对齐IP...
IPD流程图   8  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用