Python print语句如何创建局部变量

Python print语句如何创建局部变量,python,python-internals,Python,Python Internals,问题在这篇文章的末尾 第一个代码段:空的局部变量字典 def outer(): x = 1 def inner(): print "Local variables: %s" % locals() return inner() print outer() 输出: 局部变量:{} 第二个代码段:打印内部()函数并创建局部变量条目 def outer(): x = 1 def inner(): print x p

问题在这篇文章的末尾

第一个代码段:空的局部变量字典

def outer():
    x = 1
    def inner():
        print "Local variables: %s" % locals()
    return inner()
print outer()
输出: 局部变量:{}

第二个代码段:打印内部()函数并创建局部变量条目

def outer():
    x = 1
    def inner():
        print x
        print "Local variables: %s" % locals()
    return inner()
print outer()
输出:

1
Local variables: {'x': 1}
>>> outer()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 7, in outer
  File "<stdin>", line 4, in inner
UnboundLocalError: local variable 'x' referenced before assignment
>>>
第三个代码段:从内部函数中删除x:

def outer():
    x = 1
    def inner():
        print x
        print "Local variables: %s" % locals()
        del x
    return inner()
print outer()
输出:

1
Local variables: {'x': 1}
>>> outer()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 7, in outer
  File "<stdin>", line 4, in inner
UnboundLocalError: local variable 'x' referenced before assignment
>>>
>>>外部()
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
文件“”,第7行,在外部
文件“”,第4行,在内部
UnboundLocalError:赋值前引用了局部变量“x”
>>>
问题:

  • 在第二个代码段中,print语句如何创建局部变量
  • 如果它在内部函数中创建了局部变量,为什么我不能删除它

  • 有人能帮我理解一下吗。

    在Python中,除非您在函数中的任何地方(通过
    global
    语句或
    nonlocal
    语句)另外指定,否则如果您修改它(赋值给它,
    del
    它,等等),变量就在
    locals
    中*

    在第一个代码段中,您从未修改过
    x
    ,甚至从未访问过它,因此它不是本地的。事实上,它根本不存在。那很容易

    第二个版本很棘手
    x
    不是
    internal
    本地的,因为您不在
    internal
    中修改它。因此,Python开始寻找它,一个作用域一个作用域向外移动,直到找到一个包含该变量的作用域。它在
    outer
    中作为局部变量找到它。这意味着它是
    internal
    中的闭包变量或自由变量。因为函数包括闭包变量和局部变量,所以您可以看到它

    第三个版本,通过执行
    del x
    ,使
    x
    成为
    内部的本地
    **因此,它出现在
    本地
    中。但是,您尝试
    打印
    它,而没有为其分配任何内容,因此还没有值。因此,您会得到一个
    取消绑定的LocalError

    一般来说,一旦您理解了Python试图在这里实现的基本思想,通常很明显您拥有什么类型的变量。但如果不清楚的话,详细规则将在中定义


    如果您想了解闭包在封面下是如何工作的,可以从检查函数对象开始。试试这个:

    def outer():
        x = 1
        def inner():
            print x
            print "Local variables: %s" % locals()
        return inner
    inner = outer()
    print inner.func_closure
    print inner.func_code.co_freevars
    print outer.func_code.co_cellvars
    
    模块文档列出了
    函数
    代码
    和其他“隐藏”对象的所有重要成员

    使用模块查看
    外部
    内部
    的字节码也可能会有所帮助。***例如,如果您运行,您将看到本地的
    LOAD\u FAST
    ,单元格的
    LOAD\u DEREF
    ,全局的
    LOAD\u GLOBAL

    但是,如果您真的想了解所有这些是如何工作的,那么Eli Bendersky的“Python内部构件”博客上的系列文章将非常好地涵盖所有内容。(感谢Ashwini Chaudhary找到它并在评论中指出。)


    *这是在编译时检查的,而不是在执行时检查的,因此尝试将其与(例如,
    exec
    混淆会成功地混淆Python和您自己

    **请注意,
    del
    同时计为修改和访问。这可能令人惊讶,但您可以看到,
    def foo():del x
    将引发
    UnboundLocalError
    ,因为
    del
    使
    x
    成为本地,而同样的
    del
    无法找到值


    ***…假设您使用的是使用CPython样式字节码的Python实现,例如CPython本身(当然)或PyPy。

    Python通过查看编译时如何使用变量来支持嵌套作用域。您在函数中指定的变量(或在函数中使用
    导入
    绑定的变量)被视为本地变量,其他所有变量都是非本地变量。尝试删除变量时,也会将其标记为局部变量

    在父作用域中搜索非本地名称,如果未找到,则视为全局名称

    在第二个示例中,
    x
    引用父范围中的名称。您没有分配给它,因此它是一个嵌套名称,可以在本地名称空间中看到。它实际上不是一个本地名称,而是一个自由变量;它的值取自父范围

    在上一个示例中,您尝试删除
    x
    ,使其成为本地名称。在分配任何内容之前尝试引用它会导致异常

    所有这些都记录在Python参考文档中。具体而言:

    在代码块中使用名称时,将使用最近的 封闭范围。代码块可见的所有此类作用域的集合是 称为块的环境

    如果名称绑定在块中,则它是该块的局部变量。 如果名称在模块级别绑定,则它是一个全局变量。(修订) 模块代码块的变量为局部变量和全局变量。)如果 变量在代码块中使用,但未在代码块中定义,它是一个自由变量 变数

    以下构造绑定名称:函数的形式参数,
    import
    语句、类和函数定义(它们绑定 定义块中的类或函数名),以及 标识符,如果发生在分配中,则在
    的第二个位置,除了
    子句标题或在带 陈述表单的
    from的
    import
    语句。。。导入*
    binds 导入模块中定义的所有名称,以开头的名称除外 下划线。此表格只能在模块级使用

    出现在
    del
    语句中的目标也被认为是绑定的 这就是目的(尽管实际的语义是解除名称绑定)。信息技术 取消绑定封闭范围引用的名称是非法的; th