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

2024-11-21 08:33:00
admin
原创
7
摘要:问题描述:据我所知,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)
相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   601  
  华为IPD与传统研发模式的8大差异在快速变化的商业环境中,产品研发模式的选择直接决定了企业的市场响应速度和竞争力。华为作为全球领先的通信技术解决方案供应商,其成功在很大程度上得益于对产品研发模式的持续创新。华为引入并深度定制的集成产品开发(IPD)体系,相较于传统的研发模式,展现出了显著的差异和优势。本文将详细探讨华为...
IPD流程是谁发明的   7  
  如何通过IPD流程缩短产品上市时间?在快速变化的市场环境中,产品上市时间成为企业竞争力的关键因素之一。集成产品开发(IPD, Integrated Product Development)作为一种先进的产品研发管理方法,通过其结构化的流程设计和跨部门协作机制,显著缩短了产品上市时间,提高了市场响应速度。本文将深入探讨如...
华为IPD流程   9  
  在项目管理领域,IPD(Integrated Product Development,集成产品开发)流程图是连接创意、设计与市场成功的桥梁。它不仅是一个视觉工具,更是一种战略思维方式的体现,帮助团队高效协同,确保产品按时、按质、按量推向市场。尽管IPD流程图可能初看之下显得错综复杂,但只需掌握几个关键点,你便能轻松驾驭...
IPD开发流程管理   8  
  在项目管理领域,集成产品开发(IPD)流程被视为提升产品上市速度、增强团队协作与创新能力的重要工具。然而,尽管IPD流程拥有诸多优势,其实施过程中仍可能遭遇多种挑战,导致项目失败。本文旨在深入探讨八个常见的IPD流程失败原因,并提出相应的解决方法,以帮助项目管理者规避风险,确保项目成功。缺乏明确的项目目标与战略对齐IP...
IPD流程图   8  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

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

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

内置subversion和git源码管理

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

免费试用