Python字符串默认是全局的

1 投票
3 回答
5695 浏览
提问于 2025-04-16 04:51

我有一个关于Python中全局变量的问题。下面是代码。如果我在函数test中不使用global M,就会出现错误。但是为什么字符串s没有报错呢?我并没有把它声明为全局变量。

global M
M = []
s = "abc"

def test():
    ### global M
    print M 
    M.append(s)

打印M时会出现这个错误:UnboundLocalError: 在赋值之前引用了局部变量'M'

3 个回答

0

正如@Alex Martelli所说,你的代码并没有产生错误,不过我们先不讨论这个,接着@cobbal的回答来讲一下这个问题(抱歉我还不能评论)。在这里,你需要非常小心作用域的问题。

在@cobbal的回答中:

def test1():
    M = [1]

创建了一个新的变量M,这个变量只在函数test1内部有效。但是,如果他不是用M = [1]来赋值,而是用M.append(1),就像问题中那样,那么Python不会创建一个新的局部变量,而是会从函数的局部作用域向上查找,最终找到全局作用域。在全局作用域中,确实已经有一个变量M,它指向一个空列表。在这种情况下,Python会找到这个全局变量,并直接在已有的列表上添加元素,结果全局的M现在指向[1]

在第二个例子中:

def test2():
    global M
    M = [2]

使用global关键字是非常重要的,这样才能避免发生局部赋值。通过调用global,在函数的局部作用域中使用M时,会指向函数外部已经存在的[]对象。

你可以通过在不同形式的函数中插入id(M)来验证这一点,这样可以显示出哪些实现使得函数内部的M指向全局对象或局部对象。

3

我不太确定你会遇到什么错误,但看起来你对全局变量的使用有点不对。

其实,声明全局变量时并不需要(也不推荐)使用global这个关键词。它主要是在函数内部用来说明不想创建一个新的局部变量。我们来看两个不同的函数:

M = []

def test1():
    M = [1]

def test2():
    global M
    M = [2]

在test1函数里,会创建一个新的局部变量,而在test2函数里,会直接修改全局变量M。

6

如果我在函数 test 中不使用 global M,会出现错误。

你这个说法简直对!!!

>>> M = []
>>> s = "abc"
>>> 
>>> def test():
...     M.append(s)
... 
>>> M
[]
>>> test()
>>> M
['abc']

我觉得你把两个完全不同的概念搞混了:

  1. 绑定一个变量名——通常是通过赋值(也就是 =),但也可能通过其他一些语句(比如 def 等)来实现。

  2. 调用一个方法(比如 append),这个方法“可能”会改变对象的内容(当然,前提是这个对象是可以改变的,并且这个方法确实是用来改变的,比如当对象是列表,方法是 append 时)。

我不太明白为什么有人会把这两个完全不同的概念搞混,但确实有这种情况。也许是因为某些不太常见的赋值方式实际上是在“幕后”调用一个(特殊的)方法,比如,给带有限定名的变量赋值(a.b=c 实际上是在调用 type(a).__setitem__(a, b),所以是在调用一个方法,而不是重新绑定一个变量名),还有增强赋值(a+=b 实际上是在做 a = type(a).__iadd__(a, b),所以这是在调用一个方法是在重新绑定一个变量名)。

你需要使用 global(可惜)只有在你做“1”的时候:重新绑定一个变量名(包括通过增强赋值重新绑定,但包括其他特殊情况)。除非真的必要,否则尽量避免使用 global(很多人会说它从来都不是真正必要的……只是某些情况下“看起来挺方便”的东西;-)。

撰写回答