ChatGPT解决这个技术问题 Extra ChatGPT

在 Python 中使用“全局”关键字

据我了解,Python 有一个单独的函数命名空间,所以如果我想在函数中使用全局变量,我可能应该使用 global

但是,即使没有 global,我也能够访问全局变量:

>>> sub = ['0', '0', '0', '0']
>>> def getJoin():
...     return '.'.join(sub)
...
>>> getJoin()
'0.0.0.0'

我错过了什么吗?此外,以下来自 Python 文档:

全局语句中列出的名称不得定义为形式参数或 for 循环控制目标、类定义、函数定义或导入语句。

虽然形式参数和类定义对我来说很有意义,但我无法理解 for 循环控制目标和函数定义的限制。

我认为您对需要使用 global 关键字的 php 感到困惑-python 文档确认了这一点-基本上,如果未在本地上下文中定义,则将其视为全局
请注意您的措辞:Python 没有单独的函数命名空间(这意味着您可以同时拥有 def foo(): ...foo = ...)。它确实为每个函数调用创建了一个新范围。 (但这与世界上所有其他远程高级语言有何不同?)

p
phoenix

关键字 global 仅对在本地上下文中更改或创建全局变量有用,尽管创建全局变量很少被认为是一个好的解决方案。

def bob():
    me = "locally defined"    # Defined only in local context
    print(me)

bob()
print(me)     # Asking for a global variable

以上将为您提供:

locally defined
Traceback (most recent call last):
  File "file.py", line 9, in <module>
    print(me)
NameError: name 'me' is not defined

而如果您使用 global 语句,则该变量将在函数范围“之外”可用,从而有效地成为一个全局变量。

def bob():
    global me
    me = "locally defined"   # Defined locally but declared as global
    print(me)

bob()
print(me)     # Asking for a global variable

所以上面的代码会给你:

locally defined
locally defined

此外,由于 python 的特性,您还可以使用 global 在本地上下文中声明函数、类或其他对象。尽管我建议不要这样做,因为如果出现问题或需要调试,它会导致噩梦。


在这种情况下,“全球”似乎不同于其他语言认为的“全球”。在 Python 中,“全局”引用仍然在模块的范围内,需要从该模块外部作为“module.global_var”引用,而不是像人们期望的那样简单地引用“global_var”。
@juice - 在 Python 中,没有在所有命名空间中自动定义绝对 globals 之类的东西(谢天谢地)。正如您正确指出的那样,全局绑定到模块内的命名空间,但是它可以作为 from module import variableimport module.variable 导入另一个模块。在第一种情况下,导入将使变量可以作为 variable 访问,而不需要作为 module. 引用。如果它在模块范围内被认为是全局的,则取决于它的导入位置。另请参阅 nonlocal 作为 python 3 中与范围相关的新关键字。
你能解释一下为什么全局变量不是一个好的解决方案吗?我经常听到这个,但在我目前的项目中,他们似乎只是在做我需要他们做的事情。有没有更险恶的事情我没有想到?
@RobinNewhouse 关于 SO 的一些问题已经涵盖 that topic 和其他非 SO articles
@phoenix sooo global 基本上只对在本地范围内定义或启动全局变量有用?
S
SherylHohman

虽然您可以在没有 global 关键字的情况下访问全局变量,但如果您想修改它们,您必须使用 global 关键字。例如:

foo = 1
def test():
    foo = 2 # new local foo

def blub():
    global foo
    foo = 3 # changes the value of the global foo

在您的情况下,您只是访问列表 sub


有一个警告:foo = 3 没有全局工作,但 foo 在 blub 函数范围和本地再次定义不修改原始 foo 变量。这让我很困惑。
@chhantyal 如果通过工作您的意思是它不会引发错误,那么您是对的,但在 Ivo Wetzel 的上下文中,它不会按预期运行。这种行为是有用途的,但通常不是程序员想要的。
有人可以解释@chhantyal 或@democidist 的评论吗?当我尝试此代码(使用 Python 3)并调用 blub() 时,函数外部的 foo 确实按预期绑定到 3。
@LarryEngholm,blub() 按预期工作。没有的是 test():创建了新的本地 foo,而全局 foo 保留了价值。
请记住,即使没有 global 关键字,dict 值或索引列表值也会发生变化。 stackoverflow.com/questions/14323817/…
p
pycruft

这是在范围内访问名称和 binding 它之间的区别。

如果您只是查找一个变量来读取它的值,那么您可以访问全局范围和局部范围。

但是,如果您分配给名称不在本地范围内的变量,则将该名称绑定到此范围内(如果该名称也作为全局名称存在,则将其隐藏)。

如果您希望能够分配给全局名称,则需要告诉解析器使用全局名称而不是绑定新的本地名称 - 这就是“全局”关键字的作用。

绑定块中的任何位置会导致该块中任何位置的名称都被绑定,这可能会导致一些看起来很奇怪的后果(例如 UnboundLocalError 突然出现在以前的工作代码中)。

>>> a = 1
>>> def p():
    print(a) # accessing global scope, no binding going on
>>> def q():
    a = 3 # binding a name in local scope - hiding global
    print(a)
>>> def r():
    print(a) # fail - a is bound to local scope, but not assigned yet
    a = 4
>>> p()
1
>>> q()
3
>>> r()
Traceback (most recent call last):
  File "<pyshell#35>", line 1, in <module>
    r()
  File "<pyshell#32>", line 2, in r
    print(a) # fail - a is bound to local scope, but not assigned yet
UnboundLocalError: local variable 'a' referenced before assignment
>>> 

非常违反直觉,很难相信这是有效的 Python 代码
k
kindall

其他答案回答你的问题。关于 Python 中的名称要了解的另一件重要事情是,它们在每个范围内都是本地的或全局的。

考虑一下,例如:

value = 42

def doit():
    print value
    value = 0

doit()
print value

您可能会猜到 value = 0 语句将分配给一个局部变量,并且不会影响在 doit() 函数之外声明的同一变量的值。您可能会更惊讶地发现上面的代码不会运行。函数内的语句 print value 产生一个 UnboundLocalError.

原因是 Python 已经注意到,在函数的其他地方,您指定了名称 value,而且 value 也没有声明为 global。这使它成为一个局部变量。但是当您尝试打印它时,尚未定义本地名称。在这种情况下,Python 不会像其他一些语言那样将名称作为全局变量来查找。本质上,如果您在函数中定义了同名的局部变量anywhere,则无法访问全局变量。


感谢您指出了这一点。因此,只要您的本地范围未分配给存在于其外部的名称,则本地范围中的引用将使用外部名称。但是,如果您在函数中的任何位置指定了该名称,则该本地范围内的引用,即使在本地分配之前,也不要向外看。
没错,你已经明白了。 global(或 Python 3.x 中的 nonlocal)会覆盖此行为并允许您重新分配外部名称。
在其他语言中,这似乎被称为“提升”,例如:github.com/shichuan/javascript-patterns/blob/master/…
雪上加霜的是,用较新的 JavaScript 关键字 let 声明的变量是not 提升的。
访问使用 global 声明的全局变量是否更快,或者没关系?
u
user225312

访问名称和分配名称是不同的。在您的情况下,您只是在访问一个名称。

如果您在函数中分配给变量,则该变量被假定为局部变量,除非您将其声明为全局变量。如果没有,则假定它是全局的。

>>> x = 1         # global 
>>> def foo():
        print x       # accessing it, it is global

>>> foo()
1
>>> def foo():   
        x = 2        # local x
        print x 

>>> x            # global x
1
>>> foo()        # prints local x
2

m
martynas

您可以在没有关键字 global 的情况下访问全局关键字

为了能够修改它们,您需要明确声明关键字是全局的。否则,关键字将在本地范围内声明。

例子:

words = [...] 

def contains (word): 
    global words             # <- not really needed
    return (word in words) 

def add (word): 
    global words             # must specify that we're working with a global keyword
    if word not in words: 
        words += [word]

C
Community

这在 Python FAQ 中有很好的解释

Python中局部变量和全局变量的规则是什么?在 Python 中,仅在函数内部引用的变量是隐式全局的。如果一个变量在函数体内的任何地方都被赋值,除非明确声明为全局变量,否则它被假定为局部变量。虽然起初有点令人惊讶,但片刻的考虑解释了这一点。一方面,对已分配的变量要求全局性提供了防止意外副作用的障碍。另一方面,如果所有全局引用都需要全局,那么您将一直使用全局。您必须将对内置函数或导入模块组件的每个引用声明为全局。这种混乱会破坏全局声明识别副作用的有用性。

https://docs.python.org/3/faq/programming.html#what-are-the-rules-for-local-and-global-variables-in-python


J
Jesus Ramos

任何在函数外部声明的变量都被假定为全局变量,只有在从函数内部(构造函数除外)声明它们时,您必须指定该变量是全局变量。


k
kaleissin

global 使该变量对 模块(即 模块化范围)中的所有内容都可见,就像您在模块本身的顶层定义它一样。它在模块之外是不可见的,并且在设置它之前无法从模块中导入,所以不要打扰,这不是它的用途。

global 何时解决实际问题? (注意:仅在 Python 3 上检查。)

# Attempt #1, will fail
# We cannot import ``catbus`` here
# as that would lead to an import loop somewhere else,
# or importing ``catbus`` is so expensive that you don't want to 
# do it automatically  when importing this module

top_level_something_or_other = None

def foo1():
    import catbus
    # Now ``catbus`` is visible for anything else defined inside ``foo()`` 
    # at *compile time*
    bar()  # But ``bar()`` is a call, not a definition. ``catbus`` 
           # is invisible to it.

def bar():
    # `bar()` sees what is defined in the module
    # This works:
    print(top_level_something_or_other)
    # This doesn't work, we get an exception: NameError: name 'catbus' is not defined
    catbus.run()

这可以通过 global 修复:

# Attempt #2, will work
# We still cannot import ``catbus`` here
# as that would lead to an import loop somewhere else,
# or importing ``catbus`` is so expensive that you don't want to 
# do it automatically  when importing this module

top_level_something_or_other = None

def foo2():
    import catbus
    global catbus  # Now catbus is also visible to anything defined 
                   # in the top-level module *at runtime* 
    bar()

def bar():
    # `bar` sees what is defined in the module and when run what is available at run time
    # This still works:
    print(top_level_something_or_other)
    # This also works now:
    catbus.run()

如果 bar() 像这样在 foo 中定义,则不需要这样做:

# Attempt 3, will work
# We cannot import ``catbus`` here
# as that would lead to an import loop somewhere else,
# or importing ``catbus`` is so expensive that you don't want to 
# do it automatically  when importing this module

top_level_something_or_other = None

def foo3():

    def bar():
        # ``bar()`` sees what is defined in the module *and* what is defined in ``foo()``
        print(top_level_something_or_other)
        catbus.run()

    import catbus
    # Now catbus is visible for anything else defined inside foo() at *compile time*
    bar()  # Which now includes bar(), so this works

通过在 foo() 之外定义 bar(),可以将 bar() 导入到可以直接导入 catbus 的内容中,或者模拟它,例如在单元测试中。

global 是一种代码味道,但有时您需要的正是像 global 这样的肮脏 hack。无论如何,“全局”对它来说是个坏名字,因为在 python 中没有全局范围之类的东西,它一直是模块。


i
ikostia

这意味着您不应执行以下操作:

x = 1

def myfunc():
  global x

  # formal parameter
  def localfunction(x):
    return x+1

  # import statement
  import os.path as x

  # for loop control target
  for x in range(10):
    print x

  # class definition
  class x(object):
    def __init__(self):
      pass

  #function definition
  def x():
    print "I'm bad"

ikostia 列举了所有你不能使用 'x' 的东西,因为你使用了 global - docs.python.org/reference/…
@Unode:我只是在证明 NikhilRathod 在他的报价中给出的所有案例。
M
Michael

全局使变量“全局”

def out():
    global x
    x = 1
    print(x)
    return


out()

print (x)

这使得 'x' 在函数外表现得像一个普通变量。如果您将全局变量取出,则会出现错误,因为它无法在函数内打印变量。

def out():
     # Taking out the global will give you an error since the variable x is no longer 'global' or in other words: accessible for other commands
    x = 1
    print(x)
    return


out()

print (x)