【问题标题】:How to change a global variable from within a function?如何从函数中更改全局变量?
【发布时间】:2016-12-28 20:40:04
【问题描述】:

我正在尝试对定义的变量进行加减运算,但我不知道如何用新值覆盖旧值。

a = 15

def test():
    a = a +10
    print ( a )

test()

错误信息:

Traceback (most recent call last):
  File "test.py", line 7, in <module>
    test()
  File "test.py", line 4, in test
    a = a +10
UnboundLocalError: local variable 'a' referenced before assignment

【问题讨论】:

  • 加号后面可能需要一个空格。如果符号没有用空格分隔,Swift 也会报错。
  • 请将图片中的代码作为文本添加到问题本身中。
  • 这个问题包括期望的行为、特定的问题或错误,并且除非我们真的在一行上分叉,否则是重现它所需的最短代码。不可否认,这是对@approxiblue 引用的问题的欺骗,但可能是一个更好的问题,因为该问题使用了增强分配(对于初学者来说,错误消息根本没有意义),并且接受的答案不负责任地建议只使用globalnonlocal 而不是首先避免全局变量。
  • 我已经投票决定重新开放。虽然一个肯定是另一个的欺骗,但我认为引用的问题应该被标记为这个问题的欺骗,因为它不太清楚,接受的答案很糟糕,而且它目前被标记为欺骗的问题是更糟糕。有关此基本原理的背景信息,请参阅 meta.stackoverflow.com/questions/251938/…

标签: python python-3.x scope


【解决方案1】:

您尝试运行代码时遇到的错误是:

UnboundLocalError: local variable 'a' referenced before assignment

... 从表面上看,这似乎很奇怪:毕竟,上面代码 (a = 15) 中的 first 语句是一个赋值。那么,发生了什么?

实际上,发生了两件截然不同的事情,除非你已经知道它们,否则它们都不是显而易见的。

首先,你实际上有两个不同的变量:

  • 第一行中的a 是一个全局变量(之所以这么称呼,是因为它存在于全局范围内,在任何函数定义之外)。

  • 其他行中的a 是一个局部变量,这意味着它只存在于您的test() 函数中。

这两个变量完全不相关,即使它们同名。

如果在函数内部有一个分配给它的语句,则该变量是函数的局部变量 - 例如,您的 a = a +10 行。

即便如此,这个错误看起来还是很奇怪——毕竟你在test()里面做的第一件事就是赋值给a,那怎么能事先引用呢?

答案是,在赋值语句中,Python 在将= 符号右侧的所有内容赋值给左侧的名称之前,先对其进行求值——所以即使赋值是编写的 在您的代码中首先出现,a 在右侧首先被引用a +10

有两种方法可以解决这个问题。首先是告诉 Python 你真的希望 test() 中的 a 在全局范围内与 a 相同:

def test():
    global a
    a = a + 10
    print(a)

这可行,但这是编写程序的一种非常糟糕的方式。更改函数内部的全局变量很难很快地进行管理,因为您通常有很多函数,而且它们都无法确定另一个函数不会以他们不期望的方式与全局变量混淆。

更好的方法是将变量作为参数传递给函数,如下所示:

a = 15

def test(x):
    x = x + 10
    print(x)

test(a)

请注意,名称不必相同 - 您对 test() 的新定义只是说它接受一个值,然后对其进行处理。你可以传入任何你喜欢的东西——它可以是a,或者数字7,或者别的什么。事实上,如果您尽量避免在不同范围内使用同名变量,您的代码总是更容易理解。

如果您使用上面的代码,您会发现一些有趣的东西:

>>> a = 15
>>> test(a)
25
>>> a
15

a 没有改变!这是因为虽然您将其传递给 test() 并分配给了 x,但随后 x 发生了更改,而原来的 a 则保持不变。

如果你想真正改变a,你需要从函数中返回你修改后的x,然后在外面重新赋值给a

>>> a = 15
>>> 
>>> def test(x):
...     x = x + 10
...     print(x)
...     return x
... 
>>> a = test(a)
25
>>> a
25

【讨论】:

  • 在有人指出x 实际上被替换而不是更改之前……我知道。不过,为了正确回答这个问题,我已经做了相当多的准备,并决定不打开那个特定的蠕虫罐。
  • 这是一个很好的答案,谢谢。所以,可以肯定的是,真的没有办法定义测试函数,这样它实际上会改变“a”吗?即,没有办法通过一些更复杂的代码将外部重新分配步骤 a = test(a) 合并到函数本身中?
【解决方案2】:

您正在修改在函数test() 范围内创建的变量a。如果您想修改外部a,您可以这样做:

a = 15

def test():
    global a
    a = a + 1
    print(a)

test()

【讨论】:

  • 虽然使用global 解决了眼前的问题,但这是一种糟糕的编程习惯,你不应该把它作为一种解决方案教给初学者,同时指出它既不好又容易避免. global 真的不应该被那些还没有完全理解为什么这样做通常是错误的事情的人使用。
  • 你说得对,我为不表达使用 global 的错误选择提供了借口。我稍后会更新我的答案以表达这一点。非常感谢。 @ZeroPiraeus
【解决方案3】:

我会这样做:

def test(a):
    a = a +10
    return a

print(test(15))

请注意,在此提议的版本中,有些地方与您的不同。

首先,我写下的内容将创建一个函数,该函数的输入值为 a(在本例中,当我们调用该函数时设置为 15 - 已在最后一行中定义 - ),然后将值 a(原为 15)加 10 赋给对象 a,然后返回 a(已修改,现在是 25),最后,由于最后一行代码,打印出 a

print(test(15))

请注意,您所做的实际上并不是一个纯函数,可以这么说。通常我们希望函数获取一个输入值(或多个)并返回一个输入值(或多个)。在您的情况下,您的输入值实际上是空的并且没有输出值(因为您没有使用 return)。此外,您尝试在函数之外编写此输入 a (当您通过说 test(a) 调用它时,未加载值 a 并给您错误 -即在计算机眼中它是“空的”)。

此外,我鼓励你习惯于在函数中编写 return,然后在调用它时使用打印(就像我在最后一行代码中写的:print(test(15)))在函数内部使用它。最好仅在调用函数并想查看函数实际执行的操作时使用 print。

至少,这是他们在基本编程课程中向我展示的方式。这可以证明如下:如果您在函数中使用 return,该函数将为您提供一个稍后可以在其他函数中使用的值(即函数 return 是您可以使用的东西)。否则,您只会在屏幕上显示一个带有打印的数字,而计算机无法进一步处理它。

附:你也可以这样做:

def test(a):
    a +=10      
    return a

print(test(15))

【讨论】:

  • 为什么不干脆:def test(a): return a + 10
【解决方案4】:
a = 15

def test():
    global a
    a = a +10
    print ( a )
    
test()

如果你想在函数中改变局部变量的值,你需要使用 global 关键字。

【讨论】:

    【解决方案5】:

    除非使用关键字global 明确定义,否则变量的范围是块本地的。还有其他方法可以使用 globals 函数访问函数局部的全局变量

    a = 15
    
    def test():
        a = globals()['a']
        a += 10
        print ( a )
    
    test()
    

    以上示例将打印25,同时保持全局值不变,即15

    【讨论】:

      【解决方案6】:

      这里的问题是范围。 该错误基本上意味着您正在使用变量a,但它还不存在。为什么?变量a 尚未在test() 函数中声明。您需要在使用它们之前“邀请”全局变量。

      有几种方法可以在函数范围内包含变量。一种方法是将其用作这样的参数:

      def test(number):
          number = number + 10
          print ( number )
      

      然后实现为:

      test(a)
      

      您也可以使用global 关键字来显示a 是一个全局变量的函数。如何?像这样:

      def test():
          global a
          a = a + 10
          print ( a )
      

      使用global 关键字,只告诉test 在哪里寻找a。 使用第一种方法,您无法修改全局变量a,因为您制作了它的副本并且正在使用该副本。第二种方法,您在函数test()a 中所做的任何更改都会影响全局变量a

      【讨论】:

        【解决方案7】:
        # All the mumbo jumbo aside, here is an experiment 
        # to illustrate why this is something useful 
        # in the language of Python:
        a = 15    # This could be read-only, should check docs
        
        def test_1():
            b = a + 10    # It is perfectly ok to use 'a'
            print(b)
        
        def test_2():
            a = a + 10    # Refrain from attempting to change 'a'
            print(a)
        
        test_1()    # No error
        test_2()    # UnboundLocalError: ...
        

        【讨论】:

          【解决方案8】:

          您的错误与已经定义无关... 一个变量只在它所谓的作用域内有效:如果你在函数中创建一个变量,它只在这个函数中定义。

          def test():
             x=17
             print(x) # returns 17
          
          test()
          print(x) # results in an error.
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2012-09-08
            • 1970-01-01
            • 2013-03-14
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多