【问题标题】:Python function global variables?Python函数全局变量?
【发布时间】:2012-05-22 05:33:45
【问题描述】:

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

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 是否与func_a 使用和修改的x 的全局副本具有相同的值?定义后调用函数时,顺序重要吗?

【问题讨论】:

  • 请注意不要仅仅因为您在函数中分配了一个变量,python 将在分配之前处理引用。在第一次分配之前,如果您使用 x,它不会是全局的,也不是本地的。你会遇到臭名昭著的 UnboundLocalError 异常 :)

标签: python global-variables


【解决方案1】:

您可以直接访问函数内的全局变量。如果要更改该全局变量的值,请使用“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】:

    这是一个让我印象深刻的案例,它使用全局作为参数的默认值。

    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。惊喜。 Python 2.7 在第一次解析函数 func 时评估了 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
    

    【讨论】:

    【解决方案3】:

    如果您想简单地访问一个全局变量,您只需使用它的名称。但是,要更改它的值,您需要使用 global 关键字。

    例如

    global someVar
    someVar = 55
    

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

    函数定义列表的顺序无关紧要(假设它们不以某种方式相互引用),它们被调用的顺序很重要。

    【讨论】:

    • 在我给出的代码中,func_B 是否在做事 (1) 到 x 的全局副本(从 func_A 获得),(2) 到具有相同结果值的局部变量 x func_A,或者 (3) 到一个没有值且(在编译器看来)与“某个值”或 func_A 中的 x 无关的局部变量 x?
    • x in func_B 是一个局部变量,它从对func_A 的调用的返回值中获取其值 - 所以我想这将使它成为您的 (2)
    • 好的,假设 x 是由 func_A 生成的某种随机序列(即 func_A 每次运行时都会产生不同的 x。) 运行所写的程序会使 func_b 修改不同的 x比调用 func_a 时最初产生的结果是什么?如果是这样,我该如何解决?
    • 是的,如果func_A 在每次运行期间更改全局变量并将其返回给func_B 使用,那么func_B 每次都会使用更改后的值。我不确定你的“如何解决它”。您可能希望接受对当前/原始问题最有帮助的答案,然后考虑提出一个不同的问题,该问题看起来像是后续问题。
    • 其实这取决于 x 是什么。如果 x 是不可变的,那么 func_B 中的 x 将保留在其中,因为它是在本地声明的,即使它们具有相同的值。这适用于元组、整数...例如,如果它是列表的一个实例并且您执行x.append("..."),则更改的是全局变量 x,因为本地变量引用了全局变量。
    【解决方案4】:

    在 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
    

    事实上,你可以用名为x_local 的变量重写所有func_B,它的工作原理是一样的。

    顺序仅与函数执行更改全局 x 值的操作的顺序有关。因此在我们的示例中,顺序无关紧要,因为func_B 调用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 正在访问全局 x,尽管没有调用 global,并且即使 create_locally 也不使用 global,它也会创建一个本地复制,因为它正在分配一个值。

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

    【讨论】:

    【解决方案5】:

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

    您不需要它从全局变量中读取。请注意,在对象上调用方法(即使它改变了该对象中的数据)不会改变持有该对象的变量的值(缺少反射魔法)。

    【讨论】:

    • 这个措辞是不幸的。在 Python 中,分配给变量的值是一个引用,所以它在技术上是正确的(我毫不怀疑你的意思),但许多读者可能将“改变值”解释为“改变对象”,这不是案例 -- xs.append(xs.pop(0)) 没有global xs 也能正常工作。
    • @delnan 我的回答措辞谨慎,但我会澄清一下。
    【解决方案6】:

    正如其他人所指出的,当您希望函数能够修改全局变量时,您需要在函数中声明变量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
    

    【讨论】:

      猜你喜欢
      • 2022-08-02
      • 2013-05-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多