在Python中,何时需要使用global关键字?

11

好的,我一直有一个非常烦人的问题,即变量在本地设置后,在该函数之外恢复为其旧值(在这种情况下为 None),但同时我仍然可以操作其他变量而不使用“global”关键字。

我无法提供真实的代码,但它大致如下:

foo = {}
foo_foo = {}
bar = None


def changes_foo():
    ...do some stuff to foo...

class EditThread(threading.Thread):

    def __init__(self):
        setup()

    def run(self):
       for key, value in foo.items():
           do_update_task(key, value)

    def do_update_task(self, key, value):
         ...do some editing too foo...
         del foo[key]
         bar = [key, value]
         foo_foo[key] = value

def print_the_bar():
    print bar 

请注意,在foofoo_foo上的所有操作都可以正常运行,但是当我调用print_the_bar时,bar仍然为None,我在代码中添加了很多打印语句来验证do_update_task内的bar确实具有正确的值且不为None。请有人能解释一下这是为什么吗?

相关:https://dev59.com/iXRC5IYBdhLWcg3wD8xV - SeanC
我的观点是,我仍然可以对foo和foo_foo进行更改,但当我对bar进行更改时,它只存在于本地范围内。我非常愿意接受我不是经验丰富的Pythonista,我的问题是为什么我一直收到这个错误。 - Daniel Figueroa
有人能向我解释一下为什么吗?用两个词来概括:变量作用域。更详细的解释请参考链接:link - chucksmash
2
"何时需要全局变量?" -- 只有当您需要重新考虑程序设计时。 - mgilson
是的,我们都知道全局变量是纯恶魔... :P - Daniel Figueroa
可能是Do you use the "global" statement in Python?的重复问题。 - jamylak
4个回答

24

如果您只需要在函数中读取全局变量的值,则不需要使用global关键字:

x = 3
def f():
    print x
如果你曾经设置过一个全局变量的值,那么你需要使用关键字 "var" 以避免创建一个局部变量:

如果你曾经设置过一个全局变量的值,那么你需要使用关键字 "var" 以避免创建一个局部变量:

x = 3
def f():
    global x
    x = 5

f()
print x

谢谢,这个差异对我来说真的很有启示! - Alex
2
请参考此链接,了解为什么在字典中使用时,全局关键字并不像许多人期望的那样起作用。 - akhan
理解在Python中给一个名称x = 5)赋值和变异(通常伪装成赋值,如x[...] = 5)之间的区别是理解Python工作原理的基础。 - chepner

11

当你对foo和foo_foo进行操作时,你并没有改变引用关系:

foo = {}
foo['key'] = 'stuff'

foo 仍然指向之前的同一对象; 它现在只是包含了更多的数据。

bar = ['key', 'value']

这会重新指定bar指向一个新的对象(具有两个元素的列表)。

但是,当该行代码在函数内部遇到时,它会创建一个局部引用bar,除非你使用global bar。实际上,你有两个名为bar的不同变量:全局和局部。

使用global bar告诉Python使用全局版本的bar,而不是创建一个同名的新局部变量。

通常,如果你正在修改全局变量,你应该为每个变量声明global varname以避免意外创建局部变量。

或者,你可以使用一个类:

class State(object):
    def __init__(self):
        self.foo = {}
        self.foo_foo = {}
        self.bar = None

state = State()

def fn():
    state.bar = ['key', 'value']

谢谢你给出了一个很好的解释。我会尽快接受你的答案。 - Daniel Figueroa
1
只给出唯一一个没有声称在没有全局关键字的情况下无法修改全局变量的答案+1分;当然你可以修改它们,只是不能使用“=”在全局范围内重新绑定名称。 - Wooble
@Wooble 说得好,我想我会根据这个直接删除我的回答 :) - Levon

0

在函数中定义的变量只能从该函数体内访问。


0

你可以在函数内部读取全局作用域中的变量,但是如果不使用 "global" 关键字,就无法修改它们的值。

当你尝试设置 bar =[key, value] 时,一个新的 bar 变量将被添加到函数的命名空间中。从那时起,bar 引用这个新变量,而不是全局变量。

虽然你可以读取全局 bar 的值,但一旦你尝试从函数内部重新分配它的值,你实际上创建了一个新的 bar,而不是操作全局变量。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接