<p>关于Python3号的时间还没有完全的答案,所以我在这里做了一个回答。这里描述的大部分内容在Python3文档的<a href="https://docs.python.org/3/reference/executionmodel.html#resolution-of-names" rel="noreferrer">4.2.2 Resolution of names</a>中有详细说明</p>
<p>如其他答案所述,有4个基本范围,即LEGB,用于本地、封闭、全局和内置。除此之外,还有一个特殊的作用域,<strong>类主体</strong>,它不包括类内定义的方法的封闭作用域;类主体中的任何赋值都会使从此处开始的变量绑定到类主体中</p>
<p>特别是,<strong>no</strong>block语句,除了<code>def</code>和<code>class</code>之外,还创建了一个变量作用域。在Python2中,列表理解不创建变量作用域,但是在Python3中,列表理解中的循环变量是在新的作用域中创建的</p>
<p>展示班级成员的特点</p>
<pre><code>x = 0
class X(object):
y = x
x = x + 1 # x is now a variable
z = x
def method(self):
print(self.x) # -> 1
print(x) # -> 0, the global x
print(y) # -> NameError: global name 'y' is not defined
inst = X()
print(inst.x, inst.y, inst.z, x) # -> (1, 0, 1, 0)
</code></pre>
<p>因此,与函数体不同,您可以在类体中将变量重新分配到相同的名称,以获得具有相同名称的类变量;对此名称的进一步查找将解决此问题
改为使用类变量</p>
<hr/>
<p>对于许多Python新手来说,更令人惊讶的是<code>for</code>循环并没有创建变量作用域。在Python 2中,列表理解也不创建作用域(而生成器和dict理解创建作用域!),而是在函数或全局作用域中泄漏值:</p>
<pre><code>>>> [ i for i in range(5) ]
>>> i
4
</code></pre>
<p>这些理解可以作为一种巧妙的(或者糟糕的)方法,在Python 2中的lambda表达式中生成可修改的变量-lambda表达式确实会创建变量范围,就像<code>def</code>语句一样,但在lambda中不允许任何语句。赋值是Python中的语句,这意味着lambda中不允许变量赋值,但列表理解是一个表达式</p>
<p>这种行为在Python3中已得到修复-没有理解表达式或生成器泄漏变量</p>
<hr/>
<p>全局实际上是指模块范围;python的主要模块是<code>__main__</code>;所有导入的模块都可以通过<code>sys.modules</code>变量访问;要访问<code>__main__</code>,可以使用<code>sys.modules['__main__']</code>或<code>import __main__</code>;在那里访问和分配属性是完全可以接受的;它们将在主模块的全局范围内显示为变量</p>
<hr/>
<p>如果在当前作用域(类作用域除外)中分配了名称,则该名称将被视为属于该作用域,否则将被视为属于分配给变量的任何封闭作用域(可能尚未分配,或根本未分配),或最终属于全局作用域。如果变量被视为局部变量,但尚未设置或已删除,则读取变量值将导致<code>UnboundLocalError</code>,这是<code>NameError</code>的子类</p>
<pre><code>x = 5
def foobar():
print(x) # causes UnboundLocalError!
x += 1 # because assignment here makes x a local variable within the function
# call the function
foobar()
</code></pre>
<p>作用域可以声明它显式地想要修改全局(模块作用域)变量,并使用global关键字:</p>
<pre><code>x = 5
def foobar():
global x
print(x)
x += 1
foobar() # -> 5
print(x) # -> 6
</code></pre>
<p>即使它被隐藏在封闭范围内,这也是可能的:</p>
<pre><code>x = 5
y = 13
def make_closure():
x = 42
y = 911
def func():
global x # sees the global value
print(x, y)
x += 1
return func
func = make_closure()
func() # -> 5 911
print(x, y) # -> 6 13
</code></pre>
<p>在Python2中,没有简单的方法修改封闭范围中的值;通常,这是通过具有可变值来模拟的,例如长度为1的列表:</p>
<pre><code>def make_closure():
value = [0]
def get_next_value():
value[0] += 1
return value[0]
return get_next_value
get_next = make_closure()
print(get_next()) # -> 1
print(get_next()) # -> 2
</code></pre>
<p>然而,在python 3中,<code>nonlocal</code>起到了拯救作用:</p>
<pre><code>def make_closure():
value = 0
def get_next_value():
nonlocal value
value += 1
return value
return get_next_value
get_next = make_closure() # identical behavior to the previous example.
</code></pre>
<p>报告说,</p>
<blockquote>
<p>Names listed in a nonlocal statement, unlike those listed in a global statement, must refer to pre-existing bindings in an enclosing scope (the scope in which a new binding should be created cannot be determined unambiguously).</p>
</blockquote>
<p>即<code>nonlocal</code>始终指名称已绑定到的最内层外部非全局作用域(即分配给,包括用作<code>for</code>目标变量、在<code>with</code>子句中或用作函数参数)</p>
<hr/>
<p>任何不被认为是当前作用域或任何封闭作用域的局部变量都是全局变量。在模块全局字典中查找全局名称;如果未找到,则从内置模块中查找全局;模块名称从python 2更改为python 3;在Python2中它是<code>__builtin__</code>,在Python3中它现在被称为<code>builtins</code>。如果指定给buil的属性tins模块之后,它将作为可读的全局变量对任何模块可见,除非该模块使用其自己的同名全局变量对其进行阴影处理</p>
<hr/>
<p>阅读内置模块也很有用;假设您希望在文件的某些部分使用python 3样式的打印函数,但文件的其他部分仍然使用<code>print</code>语句。在Python 2.6-2.7中,您可以通过以下方法获得Python 3<code>print</code>函数:</p>
<pre><code>import __builtin__
print3 = __builtin__.__dict__['print']
</code></pre>
<p>实际上<code>from __future__ import print_function</code>并没有在Python 2中的任何地方导入<code>print</code>函数,而是在当前模块中禁用<code>print</code>语句的解析规则,像处理任何其他变量标识符一样处理<code>print</code>,从而允许在内置函数中查找<code>print</code>函数</p>