UnboundLocalError,探讨Python中的绑定
绑定
将python闭包之前,先梳理一下闭包中的绑定操作。
先看看2个相关的错误 NameError 和UnboundLocalError
When a name is not found at all, a
NameErrorexception is raised. If the name refers to a local variable that has not been bound, aUnboundLocalErrorexception is raised.UnboundLocalErroris a subclass ofNameError.
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中的绑定的更多相关文章
- 简单探讨python中的语句和语法
python程序结构 python"一切皆对象",这是接触python听到最多的总结了.在python中最基层的单位应该就是对象了,对象需要靠表达式建立处理,而表达式往往存在于语句 ...
- python中绑定码云仓库
1.File——Settings——Version Control——Git——输入git安装路径下bin下的git.exe路径——点击后面的Test测试一下,弹出版本点击ok即可 2.点击工具栏中的 ...
- python 中使用 global 引发了莫名其妙的问题
哪里出问题了 python 中,使用 global 会将全局变量设为本函数可用.同时,在函数内部访问变量会先本地再全局. 在嵌套函数中,使用 global 会产生不合常理的行为. 上代码: In [9 ...
- Python的名字绑定
Python的名字绑定 在Python中,对象是通过名字进行关联和引用的.Python通过名字绑定操作来引入名字. Python中的所谓的代码块就是一段作为执行单元的程序.比如:模块.函数.类定义.在 ...
- Python中的属性管理
Python管 理属性的方法一般有三种:操作符重载(即,__getattr__.__setattr__.__delattr__和 __getattribute__,有点类似于C++中的重载操作符).p ...
- 可爱的 Python : Python中函数式编程,第二部分
英文原文:Charming Python: Functional programming in Python, Part 2,翻译:开源中国 摘要: 本专栏继续让David对Python中的函数式编 ...
- 谈谈自己的理解:python中闭包,闭包的实质
闭包这个概念好难理解,身边朋友们好多都稀里糊涂的,稀里糊涂的林老冷希望写下这篇文章能够对稀里糊涂的伙伴们有一些帮助~ 请大家跟我理解一下,如果在一个函数的内部定义了另一个函数,外部的我们叫他外函数,内 ...
- Python中的作用域及global用法
Python 中,一个变量的作用域总是由在代码中被赋值的地方所决定的. 函数定义了本地作用域,而模块定义的是全局作用域. 如果想要在函数内定义全局作用域,需要加上global修饰符. 变量名解析:LE ...
- python中对变量的作用域LEGB、闭包、装饰器基本理解
一.作用域 在Python程序中创建.改变.查找变量名时,都是在一个保存变量名的空间中进行,我们称之为命名空间,也被称之为作用域.python的作用域是静态的,在源代码中变量名被赋值的位置决定了该变量 ...
随机推荐
- React的路由react-router
意思是:当你写一个web应用时候,应噶install的是react-router-dom,同样的,当你想写一个Native应用时候,需要install的是react-router-native,这两个 ...
- 单片机基础——使用GPIO输出点亮一个LED灯
1. 准备工作 硬件准备 开发板首先需要准备一个小熊派IoT开发板,并通过USB线与电脑连接. 软件准备 需要安装好Keil - MDK及芯片对应的包,以便编译和下载生成的代码,可参考MDK安装教程 ...
- Spring、SpringMVC、SpringBoot、SpringCloud的区别和联系
简介 Spring是一个轻量级的控制反转(IOC)和面向切面(AOP)的容器框架.Spring能够让我们编写出更简洁.易于管理.更易于测试的代码. SpringMVC是Spring的一个模块,一个we ...
- Js数组代替写循环的几个方法
简介 循环是个不可避免的结构,而且不好复用,同时循环还很难加入其他操作中.更麻烦的是,使用循环就意味着在每一个新的迭代中有更多变化需要响应. 上了循环的控制结构会使代码看起来变得复杂,故而这里提几个替 ...
- 微信小程序开发(一)开发工具推荐VSCode
虽然微信小程序官方开发工具非常优秀,但用的时间久了,会发现一些问题,比如代码编辑区小,自定义能力差,不支持插件,有时还会出现莫名其妙的bug,最不能忍的是编辑器代码提示功能不健全,这对于新手来说,很不 ...
- IPv4地址表示法详解
在TCP/IP协议中,IP地址是一个最基本的概念,本文就来参考<计算机网络>谢希仁 这本书,总结一下IPv4地址表示法的发展阶段,做个读书笔记. IP地址的编址方法共经过了三个历史阶段: ...
- CKafka如何助力腾讯课堂实现百万消息稳定互动?
疫情期间,为了保障国内学子的正常学习进度,腾讯课堂积极响应国家“停工不停学”的号召,紧急上线疫情期间专用的“老师极速版”,使广大师生足不出户,即可快速便捷的完成线上开课.面对线上课堂百万量级的互动消息 ...
- XSS-Labs(Level1-10)
Level-1 简单尝试 使用基础poc<script>alert(1)</script> 代码审计 <?php ini_set("display_errors ...
- Java高效编程:总结分享
参考资料:慕课网:Java高效编程收费实战课程.博客园.CSDN.菜鸟教程以及其他文档. 篇幅受限,不太想针对每个点都写篇博客,有的地方可能写的不是很详细,一笔带过了.如果你觉得那个点在项目中用得上可 ...
- 2000字读懂Java的来源
title: Java的来源 blog: CSDN data: Java学习路线及视频 1.Java市场 截至2020-03: Java的市场份额为17.78% 2. Java语言简介 是SUN(St ...