绑定

将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

UnboundLocalError,探讨Python中的绑定的更多相关文章

  1. 简单探讨python中的语句和语法

    python程序结构 python"一切皆对象",这是接触python听到最多的总结了.在python中最基层的单位应该就是对象了,对象需要靠表达式建立处理,而表达式往往存在于语句 ...

  2. python中绑定码云仓库

    1.File——Settings——Version Control——Git——输入git安装路径下bin下的git.exe路径——点击后面的Test测试一下,弹出版本点击ok即可 2.点击工具栏中的 ...

  3. python 中使用 global 引发了莫名其妙的问题

    哪里出问题了 python 中,使用 global 会将全局变量设为本函数可用.同时,在函数内部访问变量会先本地再全局. 在嵌套函数中,使用 global 会产生不合常理的行为. 上代码: In [9 ...

  4. Python的名字绑定

    Python的名字绑定 在Python中,对象是通过名字进行关联和引用的.Python通过名字绑定操作来引入名字. Python中的所谓的代码块就是一段作为执行单元的程序.比如:模块.函数.类定义.在 ...

  5. Python中的属性管理

    Python管 理属性的方法一般有三种:操作符重载(即,__getattr__.__setattr__.__delattr__和 __getattribute__,有点类似于C++中的重载操作符).p ...

  6. 可爱的 Python : Python中函数式编程,第二部分

    英文原文:Charming Python: Functional programming in Python, Part 2,翻译:开源中国 摘要:  本专栏继续让David对Python中的函数式编 ...

  7. 谈谈自己的理解:python中闭包,闭包的实质

    闭包这个概念好难理解,身边朋友们好多都稀里糊涂的,稀里糊涂的林老冷希望写下这篇文章能够对稀里糊涂的伙伴们有一些帮助~ 请大家跟我理解一下,如果在一个函数的内部定义了另一个函数,外部的我们叫他外函数,内 ...

  8. Python中的作用域及global用法

    Python 中,一个变量的作用域总是由在代码中被赋值的地方所决定的. 函数定义了本地作用域,而模块定义的是全局作用域. 如果想要在函数内定义全局作用域,需要加上global修饰符. 变量名解析:LE ...

  9. python中对变量的作用域LEGB、闭包、装饰器基本理解

    一.作用域 在Python程序中创建.改变.查找变量名时,都是在一个保存变量名的空间中进行,我们称之为命名空间,也被称之为作用域.python的作用域是静态的,在源代码中变量名被赋值的位置决定了该变量 ...

随机推荐

  1. Web安全相关(一):CSRF/XSRF(跨站请求伪造)和XSS(跨站脚本)

    XSS(Cross Site Script):跨站脚本,也就是javascript脚本注入,一般在站点中的富文本框,里面发表文章,留言等表单,这种表单一般是写入数据库,然后再某个页面打开. 防御: 1 ...

  2. springmvc与swagger2

    首先呢我们导入相关的jar包文件 为了方便copy我copy一份 <!-- 导入java ee jar 包 -->        <dependency>           ...

  3. day1 执行用例

    故事1 今天的工作,是执行已写好的"回馈"模块用例 每个子模块的用例都有优先级之分 肯定要先进行通过性测试,验证正常流 因此,我优先执行各个子模块优先级最高的那条用例,进行通过性测 ...

  4. MySQL字符集不一致导致性能下降25%,你敢信?

    故事是这样的: 我在对MySQL进行性能测试时,发现CPU使用率接近100%,其中80%us, 16%sys,3%wa,iostat发现磁盘iops2000以下,avgqu-sz不超过3,%util最 ...

  5. 《52讲轻松搞定网络爬虫》读书笔记 —— HTTP基本原理

    URI 和 URL URI :Uniform Resource Identifier,即统一资源标志符, URL :Universal Resource Locator,即统一资源定位符. 举栗子,加 ...

  6. anconda添加镜像源

    # anaconda 安装镜像源 ***     在使用安装 conda 安装某些包会出现慢或安装失败问题,最有效方法是修改镜     像源为国内镜像源.     之前都选用清华镜像源,但是2019年 ...

  7. DVWA(七):XSS(stored)存储型XSS攻击

    存储型XSS : 存储XSS,会把攻击者的数据存储在服务器端,攻击行为将伴随着攻击数据一直存在.提交JS攻击代码存储到数据库然后再输出. low: 观察源码: <?php if( isset( ...

  8. CUDA Pro Tip: Write Flexible Kernels with Grid-Stride Loops

    https://devblogs.nvidia.com/cuda-pro-tip-write-flexible-kernels-grid-stride-loops/ One of the most c ...

  9. Red Team 工具集之网络钓鱼和水坑攻击

    来自:信安之路(微信号:xazlsec),作者:myh0st 参考项目:https://github.com/infosecn1nja/Red-Teaming-Toolkit 上图是一个 Red Te ...

  10. adt-bundle环境搭建(Win7+Win10)

    一.adt-bundle安装包 安装包的下载地址:http://tools.android-studio.org/index.php/adt-bundle-plugin  链接中包含有windows. ...