zoukankan      html  css  js  c++  java
  • UnboundLocalError,探讨Python中的绑定

    绑定

    将python闭包之前,先梳理一下闭包中的绑定操作。

    先看看2个相关的错误 NameErrorUnboundLocalError

    When a name is not found at all, a NameError exception is raised. If the name refers to a local variable that has not been bound, a UnboundLocalError exception is raised. UnboundLocalError is a subclass of NameError.

    NameError比较好理解,即引用未定义,例如

    fun1()
    def fun1():
        pass
    

    但是UnboundLocalError却比较隐晦,意思是引用变量未绑定,注意这里的变量可能是已经定义了的。

    **If a name binding operation occurs anywhere within a code block, all uses of the name within the block are treated as references to the current block. **This can lead to errors when a name is used within a block before it is bound. This rule is subtle. Python lacks declarations and allows name binding operations to occur anywhere within a code block. The local variables of a code block can be determined by scanning the entire text of the block for name binding operations.

    下面来看看关于这种错误的隐晦bug。

    def outer_func():
        loc_var = "local variable"
        def inner_func():
            loc_var += " in inner func"
            return loc_var
        return inner_func
    
    clo_func = outer_func()
    clo_func()
    
    #UnboundLocalError: local variable 'loc_var' referenced before assignment
    

    程序在执行clo_func()的时候出了问题。
    注意语句loc_var += " in inner func"可以看作loc_var = loc_var + " in inner func", 而在求取算式loc_var + " in inner func"的时候需要变量loc_var的值,而变量loc_var在函数inner_func内是有定义的,即loc_var += " in inner func", 因此inner_func会去引用该值,但是inner_func的loc_var却没有完成绑定,因此出现了UnboundLocalError错误,有点类似递归死循环。

    由此可见,python中总是优先引用自身代码块内出现的变量,不管先后次序
    注意这里是不管先后次序,因此可能引发UnboundLocalError

    If a name binding operation occurs anywhere within a code block, all uses of the name within the block are treated as references to the current block.

    再举一个类似的例子

    import sys
    
    def add_path(new_path):
        path_list = sys.path
    
        if new_path not in path_list:
            import sys
            sys.path.append(new_path)
    add_path('./')
    

    此处path_list = sys.path引用第2个 import sys 而不是第一个, 由此导致了引用未绑定,因为sys被当成了还没有import。

    bind name:下面的操作均可视为绑定操作

    • 函数的形参
    • import声明
    • 类和函数的定义
    • 赋值操作
    • for循环首标
    • 异常捕获中相关的赋值变量

    还有一些关于UnboundLocalError的其他例子,如下

    1 def get_select_desc(name, flag, is_format = True):
    2     if flag:
    3         sel_res = 'Do select name = %s' % name
    4     return sel_res if is_format else name
    5 
    6 get_select_desc('Error', False, True)
    

    这种错误在编译的时候不会出错,但是在运行某些例子的时候就会出现UnboundLocalError。

    那如何避免这种错误呢?我觉得可以注意以下几点

    • 当局部变量与全局变量重名时

    • 当通过函数参数来选择是否绑定变量时

    这种错误和诸如C, C++等其他语言有较大差别,我觉得可能是因为在这些语言中变量的定义是明确的,如int i = 1; 。而在python中却不需要明确定义变量,因此python的每一条赋值语句在某种程度上可以说都是一次定义。但有时候这样子很不方便,于是python里也有了相应的语法,nonlocal与global定义, 但是注意nonlocal是python3的语法

    参考 https://www.cnblogs.com/yssjun/p/9873689.html

  • 相关阅读:
    DG查看恢复进度
    dataguard主备延迟多长时间的查询方法
    DG动态性能视图详解
    Django之ORM的增删改查操作流程
    IPython
    render函数和redirect函数的区别+反向解析
    http状态码
    图的基本概念
    图的遍历
    vue之webpack打包工具的使用
  • 原文地址:https://www.cnblogs.com/friedCoder/p/12571983.html
Copyright © 2011-2022 走看看