我正在使用with
块从文件中提取信息,我很惊讶with
块中声明的任何变量都是全局的。它们不应该是with
块的局部,在更改全局变量之前不应该使用global myVar
吗?毕竟,with
定义了一个代码块,对吧?
Python 没有块作用域。with
声明没有引入新的范围;语句的正文仍位于具有with
语句的同一范围内。
Python 有 4 种作用域:
- 内置作用域,定义任何模块中可用的名称,无需显式
import
。 - 全局作用域,每个模块一个。
- 非本地作用域
- 本地作用域:由函数定义。
没有其他构造定义新作用域:不是if
语句,不是for
或while
循环,不是with
语句,不是try
语句,不是class
语句。只有定义新函数(def
语句、lambda 表达式和推导(的东西才会创建新的(局部(作用域。
每个名称首先在本地作用域中查找(如果不在函数定义中,则可能是全局作用域(,然后在任何非局部作用域中查找(如果函数是在全局作用域中定义的,则可能不存在,而不是在另一个本地作用域中(,然后是全局作用域,最后是在内置作用域中。
非本地作用域只是不是当前本地作用域的作用域。对于在全局作用域定义的模块,最接近的封闭非本地作用域是全局作用域。
但是,如果一个函数是在另一个函数中定义的,则最接近的封闭非局部作用域是定义该函数的局部作用域。
函数可以嵌套得相当深,因此在当前本地作用域和可以进行名称查找的全局作用域之间可能有 0 个或更多其他本地作用域。例如
x1 = 'a'
def f1():
x2 = 'b'
def f2():
x3 = 'c'
def f3():
x4 = 'd'
print(x1 + x2 + x3 + x4)
f3()
f2()
f1()
这种混乱的输出将是abcd
.当print
语句的参数需要四个变量中每个变量的值时,每个查找都会从局部范围开始。那里只找到x4
的值;其他查找扩展到最近的封闭非本地范围,即f2
的范围。在那里找到x3
的值,因此对x1
和x2
的查找扩展到下一个非本地范围,即f1
。 找到x2
,因此f1
延长另一个停靠点。最后,在全局范围内找到x1
的值。
因此,非本地作用域与其说是一种特殊的作用域,不如说是当前执行函数的非本地作用域的名称。它将是封闭函数的本地作用域或全局作用域。
with
语句不会创建作用域(就像if, for and while
也不会创建作用域一样(。
结果,Python 将分析代码并查看您在 with 语句中进行了赋值,从而进行变量赋值。
在with
作用域之前进行初始化可能更安全,因为在 with 语句之后,我们可以安全地假设变量存在。另一方面,如果变量应该在 with 语句中赋值,那么在 with 语句之前不初始化它实际上会导致额外的检查:如果在 with 语句中以某种方式跳过赋值,Python 将出错。