【问题标题】:How do global and local variables behave in this case?在这种情况下,全局变量和局部变量如何表现?
【发布时间】:2017-08-29 13:21:29
【问题描述】:

这保存在我的文件function_local.py

x = 50

def func(x):
    print('x is', x)
    x = 2
    print('Changed local x to', x)

func(x)
print('x is still', x)

输出:

$ python function_local.py
x is 50
Changed local x to 2
x is still 50

问题:当我们打印函数内部的第一行时,为什么它打印出 50,而不是 2?即使在函数中说x = 2?

【问题讨论】:

    标签: python function global-variables variable-names


    【解决方案1】:

    如果您在函数中分配变量名(未声明 globalnonlocal)或在函数的参数列表中使用变量名,则变量名将成为函数的一部分。

    在这种情况下,你可以在函数中使用任何变量名,因为它总是引用传入的局部变量:

    x = 50
    
    def func(another_x):
        print('local x =', another_x)
        another_x = 2
        print('local x =', another_x)
        return another_x
    
    print('global x =', x)
    x = func(x)                # note that I assigned the returned value to "x" to make the change visible outside
    print('global x =', x)
    

    更多解释

    我将尝试展示我之前所说的 x 与“将成为函数的一部分”的意思。

    函数的__code__.co_varnames 保存函数的局部变量名称列表。那么让我们看看在几种情况下会发生什么:

    如果它是签名的一部分:

    def func(x):    # the name "x" is part of the argument list
        pass
    
    print(func.__code__.co_varnames)
    # ('x',)
    

    如果您分配给变量(函数中的任何位置):

    def func():
        x = 2    # assignment to name "x" inside the function
    
    print(func.__code__.co_varnames)
    # ('x',)
    

    如果您访问变量名:

    def func():
        print(x)
    
    print(func.__code__.co_varnames)
    # ()
    

    在这种情况下,它实际上会在外部范围内查找变量名,因为变量名 x 不是函数 varnames 的一部分!

    我可以理解这会让您感到困惑,因为只需在函数的任何位置添加 x=<whatever> 即可使其成为函数的一部分:

    def func():
        print(x)  # access
        x = 2     # assignment
    
    print(func.__code__.co_varnames)
    # ('x',)
    

    在这种情况下,它不会从外部范围查找变量x,因为它现在是函数的一部分,您会得到一个明显的异常(因为即使@ 987654333@ 是未分配给它的函数的一部分尚未):

    >>> func()
    UnboundLocalError: local variable 'x' referenced before assignment
    

    显然,如果您在分配给它之后访问它,它会起作用:

    def func():
        x = 2     # assignment
        print(x)  # access
    

    或者如果你在调用函数时传入:

    def func(x):  # x will be passed in
        print(x)  # access
    

    关于局部变量名的另一个重点是,你不能从外部范围设置变量,除非你告诉 Python 明确不要将 x 作为局部变量名的一部分,例如 global 或 @987654339 @:

    def func():
        global x  # or "nonlocal x"
        print(x)
        x = 2
    
    print(func.__code__.co_varnames)
    # ()
    

    当您调用 func() 时,这实际上会覆盖全局(或非局部)变量名称 x 所指的内容!

    【讨论】:

      【解决方案2】:

      在你的函数中

      def func(x):
       print('x is', x)
       x = 2
       print('Changed local x to', x)
      

      x 不是全局变量;由于主体第二行的赋值,它是一个局部变量。如果要分配给全局变量,则必须显式声明如下:

      def func(x):
       global x
       print('x is', x)
       x = 2
       print('Changed local x to', x)
      

      (注意:我错过了x 实际上是一个函数参数。请参阅https://nedbatchelder.com/text/names.html 了解对局部名称的赋值不影响全局名称的解释。)

      【讨论】:

      【解决方案3】:

      这很容易理解。

      x = 50
      
      def func(x):
          print "Local variables: "+str(locals())
          print('x is', x)
          x = 2
          print "Local variables: "+str(locals())
          print('Changed local x to', x)
      
      func(x)
      print('x is still', x)
      

      和输出

      Local variables: {'x': 50}
      'x is', 50
      Local variables: {'x': 2}
      'Changed local x to', 2
      'x is still', 50
      

      但是,如果您想在func 中定义x 之后从外部范围访问x,有一种方法,我不确定它是否会产生问题。

      def func(x):
          x = 2
          print "local x == %s" % x
          print "global x == %s" % globals().get('x')
      
      func(x)
      print "x is still %s" % x 
      

      以下将是运行的输出。

      local x == 2
      global x == 50
      x is still 50
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-06-15
        • 1970-01-01
        相关资源
        最近更新 更多