图: unsplash.com byLuis Llerena
任何Python开发人员至少都会经历一次UnboundLocalError错误。 我觉得第一次遇到这个错误很不可思议。 用这张图表达当时的心情是最合适的:
例如,下面的代码用foo函数将x递增1 :
当x=10deffoo(:x=1print ) x (foo ) )调用foo )时,堆栈日志在赋值局部变量x之前已在其他位置被引用,换句话说,x仍在当前范围内定义
跟踪后退(mostrecentcalllast ) :文件' unbound test.py ',line 8,in module foo )文件' unbound test.py ',line 4, infoox=1unboundlocalerror : local variable ' x ' referencedbeforeassignment告诉我们x是在函数foo之外定义的,但为什么没有赋值x
由于这是大多数人都会遇到的错误,Python官方将这个问题纳入了常见问题解答,并说:
thisisbecausewhenyoumakeanassignmenttoavariableinascope,thatvariablebecomeslocaltothatscopeandshadowsanysimilarlynamedvariabled
翻译后,如果xydqd在局部范围内为变量赋值,则该变量将成为局部变量,无论是否在外部初始化。 如果外部范围具有同名的变量,则这些同名的全局变量将在本地空间中隐藏。
这里,x =1等价于x=x 1,首先执行x 1操作,然后被代入x。 另一方面,在执行加法操作之前查找变量x。 根据公式的这一解释,Python认为x是函数foo的局部变量。 因为有赋值操作。 既然x是局部变量,则在执行加法操作时会抛出UnboundLocalError异常,因为它引用了x。
那么,异常该怎么解决呢? 很简单的方法。 Python提供了关键字globlal,用于显式标识x是全局变量。 如果x设置为全局变量,则在执行附加操作时在全局名称空间中搜索x。
如果在本地范围中直接引用变量而不重新赋值给变量x,则Python将按照legb (本地- -封装-全局-内置)规则按顺序搜索变量。
lst=[ 1,2,3 ] deffoo (: lst.append )5) #运行成功,lst未重新赋值,首先在本地范围中搜索,如果找不到,则在全局范围中搜索lst
def external (: x=10 def internal ) : x =1 print(x ) internal ) ) external )这是Python闭包,当执行external函数时
def external (3360 x=10 def internal ) :globalx=1print ) internal (external ) )发生新错误。 未定义所有nameerror3360global变量x。 仔细想想是啊。 x是在外部函数中定义的局部变量。 现在将internal函数的x声明为全局变量。 Python在全局范围空间中找不到x,因此出现了NameError。 那么,这个问题该怎么解决? 如果你在使用Python3,恭喜你。 Python3中添加了表示非局部变量的关键字nolocal。
在dis.dis(foo )中,可以看到Python内部字节码指令的执行过程,从字节码可以看出,以第三行代码x=x 1动作的指令是LOAD_FAST,LOAD_FAST ) x是
3load_fast0(x )3 LOAD_CONST 1 (1)1)6 INPLACE_ADD 7 STORE_FAST 0 (x ) x )4 10 LOAD_FAST 0 (x ) 13 print _ x
正文对你有帮助吗? 分享给更多的人