Python函数全局变量?


271

我知道我应该避免由于此类混淆而首先使用全局变量,但是如果我要使用它们,以下是使用它们的有效方法吗?(我正在尝试调用在单独函数中创建的变量的全局副本。)

x = "somevalue"

def func_A ():
   global x
   # Do things to x
   return x

def func_B():
   x = func_A()
   # Do things
   return x

func_A()
func_B()

请问x第二函数使用具有全球复制相同的值xfunc_a使用和修改?定义后调用函数时,顺序重要吗?


1
注意不要仅仅因为您在函数中分配了一个变量,而python将在分配之前将引用视为此类。在第一次分配之前,如果您使用x,它将不是全局变量,也不是局部变量。您将在您的脸上看到臭名昭著的UnboundLocalError异常:)
osirisgothra 2015年

Answers:


412

如果只想访问全局变量,则只需使用其名称即可。但是,要更改其值,您需要使用global关键字。

例如

global someVar
someVar = 55

这会将全局变量的值更改为55。否则,它将仅将55分配给局部变量。

函数定义列表的顺序无关紧要(假设它们在某种程度上没有相互引用),被调用的顺序确实如此。


2
在我给出的代码中,是func_B将(1)处理x的全局副本(从func_A获得),(2)处理与func_A结果的值相同的局部变量x,或者(3)一个没有值的局部变量x,(在编译器的眼中)与“某个值”或func_A中的x没有关系?
Akshat Shekhar 2012年

xin func_B是一个局部变量,它从对的返回值中获取其值func_A-所以我想这将使它成为您的(2)
Levon 2012年

好的,假设x是func_A生成的某种随机序列(即func_A每次运行都会产生不同的x。)以书面形式运行程序会使func_b修改的x与func_a被修改时的原始x不同。叫?如果是这样,我该如何解决?
Akshat Shekhar'5

1
是的,如果func_A在每次运行期间更改全局变量并将其返回func_B使用,则func_B每次将使用更改后的值工作。我不确定您的“如何解决”。您可能希望接受对当前/原始问题最有帮助的答案,然后考虑针对看起来像后续问题的问题提出另一个问题。
莱文

1
实际上,这取决于x是什么。如果x是不可变的,则func_B中的x将保留在其中,因为即使它们具有相同的值,它也会在本地声明。这适用于元组,整数...例如,如果它是列表的实例而您这样做x.append("..."),则更改的是全局变量x,因为局部变量引用了全局变量。
jadkik94 2012年

110

在Python范围内,对未在该范围内声明的变量的任何赋值都会创建一个新的局部变量,除非该变量在函数中较早地声明为使用关键字引用了全局范围的变量global

让我们看一下伪代码的修改版本,看看会发生什么:

# Here, we're creating a variable 'x', in the __main__ scope.
x = 'None!'

def func_A():
  # The below declaration lets the function know that we
  #  mean the global 'x' when we refer to that variable, not
  #  any local one

  global x
  x = 'A'
  return x

def func_B():
  # Here, we are somewhat mislead.  We're actually involving two different
  #  variables named 'x'.  One is local to func_B, the other is global.

  # By calling func_A(), we do two things: we're reassigning the value
  #  of the GLOBAL x as part of func_A, and then taking that same value
  #  since it's returned by func_A, and assigning it to a LOCAL variable
  #  named 'x'.     
  x = func_A() # look at this as: x_local = func_A()

  # Here, we're assigning the value of 'B' to the LOCAL x.
  x = 'B' # look at this as: x_local = 'B'

  return x # look at this as: return x_local

实际上,您可以func_B使用named变量重写所有变量,x_local并且其工作方式相同。

该顺序仅与函数执行更改全局x值的操作的顺序一样重要。因此,在我们的示例中,顺序没有关系,因为func_Bcall func_A。在此示例中,顺序很重要:

def a():
  global foo
  foo = 'A'

def b():
  global foo
  foo = 'B'

b()
a()
print foo
# prints 'A' because a() was the last function to modify 'foo'.

请注意,global仅需要修改全局对象。您仍然可以从函数内部访问它们而无需声明global。因此,我们有:

x = 5

def access_only():
  return x
  # This returns whatever the global value of 'x' is

def modify():
  global x
  x = 'modified'
  return x
  # This function makes the global 'x' equal to 'modified', and then returns that value

def create_locally():
  x = 'local!'
  return x
  # This function creates a new local variable named 'x', and sets it as 'local',
  #  and returns that.  The global 'x' is untouched.

请注意,create_locallyaccess_only- 之间的区别access_only是尽管未调用global,但仍访问全局x ,即使create_locally不使用global任何一个,它也会由于分配值而创建本地副本。

这里的困惑是为什么您不应该使用全局变量。


2
我不认为这在实践中会造成很大的混乱,您只需要了解python的作用域规则即可
Casey Kuball

20

正如其他人指出的那样,global当您希望该函数能够修改全局变量时,需要在该函数中声明一个变量。如果您只想访问它,则不需要global

为了对此进行更详细的说明,“修改”的含义是:如果要重新绑定全局名称,使其指向另一个对象,则必须global在函数中声明该名称。

许多修改(更改)对象的操作不会重新绑定全局名称以指向其他对象,因此它们在不声明函数名称的情况下都是有效global的。

d = {}
l = []
o = type("object", (object,), {})()

def valid():     # these are all valid without declaring any names global!
   d[0] = 1      # changes what's in d, but d still points to the same object
   d[0] += 1     # ditto
   d.clear()     # ditto! d is now empty but it`s still the same object!
   l.append(0)   # l is still the same list but has an additional member
   o.test = 1    # creating new attribute on o, but o is still the same object

8

这是一种使用全局变量作为参数默认值的情况,吸引了我。

globVar = None    # initialize value of global variable

def func(param = globVar):   # use globVar as default value for param
    print 'param =', param, 'globVar =', globVar  # display values

def test():
    global globVar
    globVar = 42  # change value of global
    func()

test()
=========
output: param = None, globVar = 42

我曾期望param的值为42。首次解析函数func时,Python 2.7评估了globVar的值。更改globVar的值不会影响分配给param的默认值。如下所示,延迟评估可以按照我的需要进行。

def func(param = eval('globVar')):       # this seems to work
    print 'param =', param, 'globVar =', globVar  # display values

或者,如果您想安全,

def func(param = None)):
    if param == None:
        param = globVar
    print 'param =', param, 'globVar =', globVar  # display values

那使我想起了分配一个空列表作为默认值的问题。并且,如示例中所示,用于is检查是否为None,而不是常规比较==
berna1111

6

您可以直接访问函数内部的全局变量。如果要更改该全局变量的值,请使用“ global variable_name”。请参见以下示例:

var = 1
def global_var_change():
      global var
      var = "value changed"
global_var_change() #call the function for changes
print var

一般来说,这不是一个好的编程习惯。通过破坏名称空间逻辑,代码可能变得难以理解和调试。


2

global当您希望更改分配给全局变量的值时,必须使用声明。

您不需要它来读取全局变量。请注意,在对象上调用方法(即使它更改了该对象内的数据)也不会更改保存该对象的变量的值(缺少反射魔术)。


2
这个措词很不幸。在Python中,分配给变量的值是一个引用,因此从技术上讲是正确的(我毫无疑问是您的意思),但是许多读者可能会将“更改值”解释为“使对象突变”,但这并不是的情况- xs.append(xs.pop(0))没有的情况下很好的工作global xs

@delnan我的答案措辞谨慎,但我会澄清。
马钦(Marcin)2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.