欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Python UnboundLocalError和NameError錯誤根源案例解析

 更新時間:2018年10月31日 09:31:47   作者:alpha_panda  
這篇文章主要介紹了Python UnboundLocalError和NameError錯誤根源解析,本文通過案例分析實例代碼相結(jié)合的形式給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下

如果代碼風格相對而言不是那么的pythonic,或許很少碰到這類錯誤。當然并不是不鼓勵使用一些python語言的技巧。如果遇到這這種類型的錯誤,說明我們對python中變量引用相關(guān)部分有不當?shù)恼J識和理解。而這又是對理解python相關(guān)概念比較重要的。這也是本文寫作的原因。

 本文為理解閉包相關(guān)概念的做鋪墊,后續(xù)會詳細深入的整理出閉包相關(guān)的博文,敬請關(guān)注。

1.案例分析

在整理閉包相關(guān)概念的過程中,經(jīng)常發(fā)現(xiàn)UnboundLocalError和NameError這兩個錯誤,剛開始遇到的時候可能很困惑,對這樣的錯誤無從下手。

1.1 案例一:

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()

錯誤提示:

Traceback (most recent call last):
  File "G:\Project Files\Python Test\Main.py", line 238, in <module>
    clo_func()
  File "G:\Project Files\Python Test\Main.py", line 233, in inner_func
    loc_var += " in inner func"
UnboundLocalError: local variable 'loc_var' referenced before assignment

1.2 案例二:

 def get_select_desc(name, flag, is_format = True):
   if flag:
     sel_res = 'Do select name = %s' % name
  return sel_res if is_format else name 
 get_select_desc('Error', False, True)

錯誤提示:

Traceback (most recent call last):
  File "G:\Project Files\Python Test\Main.py", line 247, in <module>
    get_select_desc('Error', False, True)
  File "G:\Project Files\Python Test\Main.py", line 245, in get_select_desc
    return sel_res if is_format else name
UnboundLocalError: local variable 'sel_res' referenced before assignment

1.3 案例三:

def outer_func(out_flag):
  if out_flag:
    loc_var1 = 'local variable with flag'
  else:
    loc_var2 = 'local variable without flag'
  def inner_func(in_flag):
    return loc_var1 if in_flag else loc_var2
  return inner_func

clo_func = outer_func(True)
print clo_func(False)

  錯誤提示:

Traceback (most recent call last):
  File "G:\Project Files\Python Test\Main.py", line 260, in <module>
    print clo_func(False)
  File "G:\Project Files\Python Test\Main.py", line 256, in inner_func
    return loc_var1 if in_flag else loc_var2
NameError: free variable 'loc_var2' referenced before assignment in enclosing scope

 上面的三個例子可能顯得有點矯揉造作,但是實際上類似錯誤的代碼都或多或少可以在上面的例子中找到影子。這里僅僅為了說明相關(guān)概念,對例子本身的合理性不必做過多的關(guān)注。

2.錯誤原因

由于python中沒有變量、函數(shù)或者類的聲明概念。按照C或者C++的習慣編寫python,或許很難發(fā)現(xiàn)錯誤的根源在哪。

首先看一下這類錯誤的官方解釋:

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。如果該名字是一個還沒有被綁定的局部變量名,那么該類型的錯誤是NameError中的UnboundLocalError錯誤。

下面的這種NameError類型的錯誤或許還好理解一些:

 my_function()
 def my_function():
   pass

 如果說python解釋器執(zhí)行到def my_function()時才綁定到my_function,而my_function此時也表示的是內(nèi)存中函數(shù)執(zhí)行的入口。因此在此之前使用my_function均會有NameError錯誤。

那么上面的例子中使用變量前,都有賦值操作(可視為一種綁定操作,后面會講),為什么引用時會出錯?定義也可判斷可見性

如果說是因為賦值操作沒有執(zhí)行,那么為什么該變量名在局部命名空間是可見的?(不可見的話,會有這類錯誤:NameError: global name 'xxx' is not defined,根據(jù)UnboundLocalError定義也可判斷可見性)

問題到底出在哪里?怎樣正確理解上面三個例子中的錯誤?

3. 可見性與綁定

簡單起見,這里不介紹命名空間與變量查找規(guī)則LGB相關(guān)的概念。

在C或者C++中,只要聲明并定義了一個變量或者函數(shù),便可以直接使用。但是在Python中要想引用一個name,該name必須要可見而且是綁定的。

先了解一下幾個概念:

1.code block:作為一個單元(Unit)被執(zhí)行的一段python程序文本。例如一個模塊、函數(shù)體和類的定義等。
2.scope:在一個code block中定義name的可見性;
3.block's environment:對于一個code block,其所有scope中可見的name的集合構(gòu)成block的環(huán)境。
4.bind name:下面的操作均可視為綁定操作 •函數(shù)的形參

•import聲明

•類和函數(shù)的定義

•賦值操作

•for循環(huán)首標

•異常捕獲中相關(guān)的賦值變量

5.local variable:如果name在一個block中被綁定,該變量便是該block的一個local variable。
6.global variable:如果name在一個module中被綁定,該變量便稱為一個global variable。
7.free variable: 如果一個name在一個block中被引用,但沒有在該代碼塊中被定義,那么便稱為該變量為一個free variable。

Free variable是一個比較重要的概念,在閉包中引用的父函數(shù)中的局部變量是一個free variable,而且該free variable被存放在一個cell對象中。這個會在閉包相關(guān)的文章中介紹。

scope在函數(shù)中具有可擴展性,但在類定義中不具有可擴展性。

分析整理一下:

經(jīng)過上面的一些概念介紹我們知道了,一個變量只要在其code block中有綁定操作,那么在code block的scope中便包含有這個變量。

也就是綁定操作決定了,被綁定的name在當前scope(如果是函數(shù)的話,也包括其中定義的scope)中是可見的,哪怕是在name進行真正的綁定操作之前。

這里就會有一個問題,那就是如果在綁定name操作之前引用了該name,那么就會出現(xiàn)問題,即使該name是可見的。

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.

注意上面官方描述的第一句和最后一句話。

總的來說就是在一個code block中,所有綁定操作中被綁定的name均可以視為一個local variable;但是直到綁定操作被執(zhí)行之后才可以真正的引用該name。

有了這些概念,下面逐一分析一下上面的三個案例。

4. 錯誤解析

4.1 案例一分析

在outer_func中我們定義了變量loc_var,因為賦值是一種綁定操作,因此loc_var具有可見性,并且被綁定到了具體的字符串對象。

但是在其中定義的函數(shù)inner_func中卻并不能引用,函數(shù)中的scope不是可以擴展到其內(nèi)定義的所有scope中嗎?

下面在在來看一下官方的兩段文字描述:

When a name is used in a code block, it is resolved using the nearest enclosing scope.

這段話告訴我們當一個name被引用時,他會在其最近的scope中尋找被引用name的定義。顯然loc_var += " in inner func"這個語句中的loc_var會先在內(nèi)部函數(shù)inner_func中找尋name loc_var。

該語句實際上等價于loc_var = loc_var + " in inner func",等號右邊的loc_var變量會首先被使用,但這里并不會使用outer_func中定義的loc_var,因為在函數(shù)inner_func的scope中有l(wèi)oc_var的賦值操作,因此這個變量在inner_func的scope中作為inner_func的一個local variable是可見的。

但是要等該語句執(zhí)行完成,才能真正綁定loc_var。也就是此語句中我們使用了inner_func block中的被綁定之前的一個local variable。根據(jù)上面錯誤類型的定義,這是一個UnboundLocalError.

4.2 案例二分析

在這個例子中,看上去好像有問題,但是又不知道怎么解釋。

引用發(fā)生在綁定操作之后,該變量應(yīng)該可以被正常引用。但問題就在于賦值語句(綁定操作)不一定被執(zhí)行。如果沒有綁定操作那么對變量的引用肯定會有問題,這個前面已經(jīng)解釋過了。

但是還有一個疑問可能在于,如果賦值語句沒有被執(zhí)行,那么變量在當前block中為什么是可見的?

關(guān)于這個問題其實可以被上面的一段話解釋:The local variables of a code block can be determined by scanning the entire text of the block for name binding operations.

只要有綁定操作(不管實際有沒有被執(zhí)行),那么被綁定的name可以作為一個local variable,也就是在當前block中是可見的。scanning text發(fā)生在代碼被執(zhí)行前。

4.2 案例三分析

這個例子主要說明了一類對free variable引用的問題。同時這個例子也展示了一個free variable的使用。

在創(chuàng)建閉包inner_func時,loc_var1和loc_var2作為父函數(shù)outer_func中的兩個local variable在其內(nèi)部inner_func的scope中是可見的。返回閉包之后在閉包中被引用outer_func中的local variable將作為稱為一個free variable.

閉包中的free variable可不可以被引用取決于它們有沒有被綁定到具體的對象。

5. 引申案例

下面再來看一個例子:

 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('./')

平時不經(jīng)意間可能就會犯上面的這個錯誤,這也是一個典型的UnboundLocalError錯誤。如果仔細的閱讀并理解上面的分析過程,相信應(yīng)給能夠理解這個錯誤的原因。如果還不太清除,請再閱讀一遍 :-)

總結(jié)

以上所述是小編給大家介紹的Python UnboundLocalError和NameError錯誤根源案例解析,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!

相關(guān)文章

  • 關(guān)于Python函數(shù)的定義和參數(shù)

    關(guān)于Python函數(shù)的定義和參數(shù)

    這篇文章主要介紹了關(guān)于Python函數(shù)的定義和參數(shù),Python中的函數(shù)我們可以理解成是一種具有功能的包裝塊,也就是封裝具有某一種功能的代碼塊,需要的朋友可以參考下
    2023-04-04
  • numpy中的norm()函數(shù)求范數(shù)實例

    numpy中的norm()函數(shù)求范數(shù)實例

    這篇文章主要介紹了numpy中的norm()函數(shù)求范數(shù)實例,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • Python列表(List)知識點總結(jié)

    Python列表(List)知識點總結(jié)

    在本篇文章中小編給大家分享了關(guān)于Python列表(List)知識點一直對應(yīng)的實例內(nèi)容,需要的朋友們學(xué)習下。
    2019-02-02
  • pyecharts如何使用formatter回調(diào)函數(shù)的問題

    pyecharts如何使用formatter回調(diào)函數(shù)的問題

    這篇文章主要介紹了pyecharts如何使用formatter回調(diào)函數(shù)的問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-08-08
  • python如何代碼集體右移

    python如何代碼集體右移

    在本篇文章里小編給各位分享的是一篇關(guān)于python如何代碼集體右移的相關(guān)知識點文章,需要的朋友們可以學(xué)習下。
    2020-07-07
  • python write無法寫入文件的解決方法

    python write無法寫入文件的解決方法

    今天小編就為大家分享一篇python write無法寫入文件的解決方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-01-01
  • 使用Python快速制作可視化報表的方法

    使用Python快速制作可視化報表的方法

    今天小編就為大家分享一篇使用Python快速制作可視化報表的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-02-02
  • 安裝Python的web.py框架并從hello world開始編程

    安裝Python的web.py框架并從hello world開始編程

    這篇文章主要介紹了安裝Python的web.py框架并從hello world開始編程,web.py的作者年輕的Aaron Swartz已經(jīng)離世,緬懷大神,需要的朋友可以參考下
    2015-04-04
  • 深入解析Python中的變量和賦值運算符

    深入解析Python中的變量和賦值運算符

    這篇文章主要介紹了深入解析Python中的變量和賦值運算符,是Python入門學(xué)習中的基礎(chǔ)知識,需要的朋友可以參考下
    2015-10-10
  • python使用Turtle庫畫畫寫名字

    python使用Turtle庫畫畫寫名字

    Turtle庫是Python語言中一個很流行的繪制圖像的函數(shù)庫,本篇文章小編就帶大家學(xué)習python利用Turtle庫畫畫寫名字的相關(guān)資料,需要的朋友可以參考下面文章的具體內(nèi)容
    2021-09-09

最新評論