为什么不需要“global”关键字来访问全局变量?

2024-11-21 08:33:00
admin
原创
165
摘要:问题描述:据我所知,Python 有一个用于函数的单独命名空间,所以如果我想在函数中使用全局变量,我应该使用global。但是,即使没有,我也可以访问全局变量global:>>> sub = ['0', '0', '0', '0'] >>> def getJoin(): ....

问题描述:

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

但是,即使没有,我也可以访问全局变量global

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

为什么这会起作用?


另请参阅第一次使用后重新分配局部变量时出现的 UnboundLocalError,以了解在未指定的情况下尝试分配全局变量时发生的错误global。有关如何使用全局变量的一般问题,请参阅在函数中使用全局变量。


解决方案 1:

该关键字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它在本地上下文中声明函数、类或其他对象。但我不建议这样做,因为如果出现问题或需要调试,它会带来噩梦。

解决方案 2:

虽然无需使用关键字即可访问全局变量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

解决方案 3:

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

如果您只是查找变量来读取其值,那么您可以访问全局和本地范围。

但是,如果您分配给一个变量的名称不在本地范围内,那么您就是将该名称绑定到此范围(并且如果该名称也作为全局名称存在,那么您将隐藏它)。

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

在块中的任何位置进行绑定都会导致该块中所有位置的名称都被绑定,这可能会导致一些相当奇怪的后果(例如,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
>>> 

解决方案 4:

其他答案回答了你的问题。关于 Python 中的名称,另一个需要了解的重要事项是,它们根据作用域的不同,要么是本地的,要么是全局的。

例如:

value = 42

def doit():
    print value
    value = 0

doit()
print value

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

原因是 Python 注意到,在函数的其他地方,你分配了名称value,并且也value没有在任何地方声明global。这使它成为一个局部变量。但是当你尝试打印它时,本地名称尚未定义。在这种情况下,Python不会像其他一些语言那样回退到将名称作为全局变量进行查找。本质上,如果你在函数的任何地方定义了同名的局部变量,你就无法访问全局变量。

解决方案 5:

访问名称和分配名称是不同的。 在您的例子中,您只是访问名称。

如果在函数内赋值给变量,除非声明为全局变量,否则该变量将被视为局部变量。如果没有声明全局变量,则将被视为全局变量。

>>> 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

解决方案 6:

  • 无需关键字即可访问全局关键字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]

解决方案 7:

Python FAQ 中对此进行了很好的解释

Python 中局部变量和全局变量的规则是什么?

在 Python 中,仅在函数内部引用的变量隐式为全局变量。如果在函数主体的任何地方为变量赋值,则除非明确声明为全局变量,否则该变量将被视为局部变量。

虽然一开始有点令人惊讶,但稍加考虑就能解释这一点。一方面,要求global分配变量可以防止意外的副作用。另一方面,如果global要求所有全局引用都是这样,那么您将global一直使用。您必须将对global内置函数或导入模块组件的每个引用声明为。这种混乱会破坏声明global在识别副作用方面的实用性。

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

解决方案 8:

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

通过定义bar()外部foo()bar()可以将其导入到可以直接导入的东西中catbus,或者模拟它,就像在单元测试中一样。

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

解决方案 9:

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

解决方案 10:

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

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"

解决方案 11:

Global 使变量“全局”

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)
相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用