访问函数外的变量

7 投票
4 回答
1737 浏览
提问于 2025-04-30 02:44

我对Python还比较陌生,但对C++有点经验,所以下面这个代码示例让我有点困惑。

def foo():
    y = x
    print y

x = 5
foo()

运行这段代码会打印出值5。那么,变量x是怎么在foo()函数里面被知道的呢?在C++中,上面的代码是无法运行的,只有这样做才行:

#include <iostream>

int x = 5;
void foo()
{
    std::cout << "x = " << x << std::endl;
}

int main()
{
    foo();
    return 0;
}

因为在这里,x是一个在全局范围内的变量,它是在foo()之前声明(和定义)的。在Python中,它能正常工作是因为x被添加到了全局符号表里吗?

谢谢大家的帮助!

暂无标签

4 个回答

0

据我所知,Python(就像Lua一样)把全局变量当作在你定义它们的时候就一直存在的东西。所以,当你定义了一个函数并把x设置为5后,Python认为这两个东西(函数和变量)都存在,并且一直都存在。当你调用foo()的时候,它会在全局和局部的命名空间里找一个叫'x'的变量,结果会找到一个值为5的变量,然后把这个值打印出来。

2

希望你觉得这段代码有用。

def foo():
    y = x # y becames local while x ..is found as a global
    print "globals=", globals()
    print "locals=", locals()
    print y

x = 5 # here you declare variable x with global scope and with value 5
foo()

--------------------
$ python test.py
globals= {'__builtins__': <module '__builtin__' (built-in)>, '__file__': 'test.py', '__package__': None, 'x': 5, '__name__': '__main__', 'foo': <function foo at 0x7f0d4cbf05f0>, '__doc__': None}
locals= {'y': 5}
5
3

这两种语言的主要区别在于它们是如何查找变量的。

在C++中,代码是一次性编译的。当编译器读取代码中的foo时,它看到x,但还不知道这个标识符是什么。它可能是任何类型的变量,也可能是一个函数,或者只是个拼写错误。如果编译器之前没有看到x的定义,也就是没有解释x是什么类型的东西(虽然不一定是它的实际),那么它会立刻报错。

而在Python中,当看到x时,它知道这就是一个名字,也就是一个标识符,因为它符合相应的标记类型,并且不是语言的关键字。在Python中,一切都是对象,这是真的——这也包括函数。Python在编译时没有类型检查,所以我们不在乎x是整数、函数还是别的什么——这些都可以用同样的方式处理。(是的,你可以打印函数,但这不会给你任何有用的信息,比如原始代码;它只会给你一个包含类型、名称和对象ID的一些基本信息的占位符)。实际上,Python的变量没有类型(甚至没有像Haskell那样的隐式类型),只有Python的才有类型。

另外,也没有检查x是否真的存在的有效性检查,因为这也不可能——在Python中,有办法动态创建名字(一般来说,请不要这样做)。

不过,在编译时可以进行足够的分析来确定x不是一个局部变量,因此Python会生成代码,指示“查找一个名为x的全局变量并使用它”。任何由此产生的错误会在函数foo实际运行时发生,以异常的形式出现。如果x作为全局变量实际上不存在,它会引发NameError;如果存在但对应的对象类型错误(通常对于print来说是不可能的,但对于+来说是可能的),则会引发TypeError;如果类型正确但值无效,通常会引发ValueError或其子类型(例如,试图用无效的数字索引访问list会引发IndexError,这是ValueError的一个子类型)。

4

在全局范围内的所有东西都可以在函数内部读取。这是必须的:在Python中,指向变量的名字和指向函数的名字没有区别,所以如果这不成立,你甚至无法调用函数。

但是,如果你想修改变量x,就需要使用global这个关键词。

至于为什么在函数定义后变量也能正常工作:Python并不会在编译时就解决这些引用,而是在函数被调用时才会去处理。因为Python是动态的,所以事先无法知道一个变量是否已经定义。

撰写回答