在if语句中初始化的变量的作用域是什么?


266

我是Python的新手,所以这可能是一个简单的范围界定问题。Python文件(模块)中的以下代码使我有些困惑:

if __name__ == '__main__':
    x = 1

print x

在我使用过的其他语言中,此代码将引发异常,因为该x变量是if语句的局部变量,不应在其外部存在。但是此代码将执行并打印1。任何人都可以解释此行为吗?是否在模块中创建的所有变量都是全局的/可用于整个模块?


17
另一种怪癖,你可能不知道的:如果if上述声明不为真(即,__name__不是 '__main__',例如当您导入模块,而不是执行它顶级的),那么x将永远不会被束缚,以及随后的print x声明会抛出一个NameError: name 'x' is not defined
圣诞老人

Answers:


301

Python变量的作用域是分配给它们的最里面的函数,类或模块。控制块(如ifwhile块)不计在内,因此在内分配的变量的if作用域仍限于函数,类或模块。

(由生成器表达式或list / set / dict理解定义的隐式函数与lambda表达式一样进行计数。您不能将赋值语句填充到其中任何一个中,但是lambda参数和for子句目标是隐式赋值。)



105

是的,它们在同一个“本地范围”中,实际上这样的代码在Python中很常见:

if condition:
  x = 'something'
else:
  x = 'something else'

use(x)

请注意,x不会在条件之前声明或初始化它,例如在C或Java中。

换句话说,Python没有块级作用域。不过,请注意以下示例

if False:
    x = 3
print(x)

这显然会引发NameError例外。


42

python中的作用域遵循以下顺序:

  • 搜索本地范围

  • 搜索所有封闭函数的范围

  • 搜索全球范围

  • 搜索内置

来源

请注意,if未列出其他循环/分支构造-仅类,函数和模块在Python中提供了作用域,因此,在if块中声明的任何内容都与在该块之外清除的任何内容具有相同的作用域。在编译时不检查变量,这就是为什么其他语言会引发异常的原因。在python中,只要变量在您需要时存在,就不会抛出异常。


9

正如Eli所说,Python不需要变量声明。在C中,您会说:

int x;
if(something)
    x = 1;
else
    x = 2;

但在Python中声明是隐式的,因此当您分配给x时,它会自动声明。这是因为Python是动态类型的-它无法在静态类型的语言中工作,因为取决于所使用的路径,可能会在未声明的情况下使用变量。这将在编译时以静态类型的语言捕获,但是允许使用动态类型的语言。

if由于此问题,静态类型的语言仅限于必须在语句之外声明变量的唯一原因。拥抱动态!


9

与C之类的语言不同,Python变量在它所出现的整个函数(或类,模块)的范围内,而不仅仅是在最内部的“块”中。就像您int x在函数(或类,模块)的顶部声明的一样,只是在Python中不必声明变量。

请注意,x仅在运行时(即,进入print x语句时)检查变量的存在。如果__name__不相等"__main__",则会出现异常:NameError: name 'x' is not defined


类不会创建作用域;创建时将类中的“局部”变量简单地添加到类的字典中。
chepner


2

您是从命令行执行此代码的,因此if条件为true且x已设置。比较:

>>> if False:
    y = 42


>>> y
Traceback (most recent call last):
  File "<pyshell#6>", line 1, in <module>
    y
NameError: name 'y' is not defined

0

请注意,由于仅在运行时检查Python类型,因此您可以使用如下代码:

if True:
    x = 2
    y = 4
else:
    x = "One"
    y = "Two"
print(x + y)

但是我很难考虑由于类型问题而导致代码无错误运行的其他方式。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.