函数外部如何访问变量

7

我对Python还比较陌生,但在C++方面有些经验,这就是为什么下面的代码示例让我感到困惑的原因。

def foo():
    y = x
    print y

x = 5
foo()

运行此代码会打印值为5。如何在foo()函数中知道变量x的值? 如果我们使用C++,上面的代码将无法运行,正确的写法应该是:
#include <iostream>

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

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

因为此处的变量 x 是在 foo() 之前在全局作用域中声明(并定义)的。它能够在 Python 中正常工作是因为 x 被添加到了全局符号表中。
谢谢您的帮助!

2
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - juanchopanza
你也应该看一下这个:https://docs.python.org/2.7/tutorial/classes.html#python-scopes-and-namespaces - Jayanth Koushik
@juanchopanza 是正确的。从globals()函数获取的字典包含'x': 5。 - jensa
4个回答

4

全局作用域中的所有内容都可以在函数内部进行读取。这是必须的:在Python中,指向变量和指向函数的名称之间没有区别,因此,如果这样做不起作用,则甚至无法调用函数。

但是,如果您想修改x,则需要使用global关键字。

至于为什么在函数之后定义变量时它能工作:Python不会在编译时尝试解析引用,而是在调用函数时执行:因为Python中的所有内容都是动态的,所以无法提前知道变量是否被定义。


但是如果你想修改 x,你需要使用全局关键字。谢谢,知道这点非常有用! - jensa

3
真正的区别在于两种语言中的变量查找方式。
在C++中,代码一次编译通过。当编译器读取foo的代码时,它看到x,并不知道这个标识符是什么意思。它可能是任何类型的变量,也可能是一个函数,或者可能是一个排版错误。如果它还没有看到关于x的定义——解释x是什么类型的信息,尽管不一定是它的实际值——那么它将立即报错。
当Python看到x时,它知道这是一个名字——即标识符——因为它与适当的令牌类型匹配,而且不是语言关键字。在Python中,一切都是对象,我们真的是这样说的——包括函数。在编译时没有类型检查,所以我们不关心x是整数、函数还是其他类型——所有这些都可以用相同的方式处理。(是的,你可以打印函数——但它不会向你展示有用的任何信息,如原始代码;它只会给你一个带有有关类型、名称和对象ID的基本信息的存根)。真的不能进行任何类型检查,因为Python的变量没有类型(即使是隐含的类型,像Haskell这样的类型推导语言中一样)——Python的值有类型。
也没有有效性检查来确定x是否存在,因为这也是不可能的——在Python中有一些动态创建名称的方式(一般而言,请不要这样做)。
但是,编译时可以进行足够的分析以确定x不是本地变量,因此Python生成的代码是“查找名为x的全局变量并使用它”。任何结果错误都以异常形式在foo运行时出现。如果x实际上不存在作为全局,则会引发NameError;如果它存在,但相应的对象类型错误(通常对于print来说是不可能的,但对于+来说是可能的),则会引发TypeError,如果它是正确的类型但是无效的值,它通常会引发ValueError或其子类型(例如,list中的无效数字索引将引发IndexError,这是ValueError的子类型)。

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

1
我基本上做了和你一样的测试,并得到了相同的结果。谢谢! - jensa

0
据我所知,Python (就像Lua一样)在定义全局变量后会将它们视为一直存在。因此,在定义函数并将x设置为5之后,它们都存在且对Python来说一直存在。当调用foo()时,它会在全局和本地命名空间中搜索名为'x'的变量,并找到一个值为5的变量,然后将其打印出来。

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