2017-04-25 30 views
1

在構建參數化裝飾器時,我還沒有意識到在Python中不允許在嵌套函數中傳遞參數的重新賦值。進一步看,我意識到這對簡單的功能也是如此。我演示已經降低到以下嵌套函數:在Python的函數調用中進行賦值嗎?

def a(s): 
    def b(): 
     def c(): 
#    nonlocal s       # fix 
      print(s) 
#    while s: 
#     s -= 1       # uncommenting raises UnboundLocalError 
      print(s) 
      return None 
     return c() 
    return b() 

a(3) 
# 3 
# 3 

我想以下期望的輸出通過將評價while循環:

a(3) 
# 3 
# 0 

接着,在取消對while環路的兩行給出出現以下錯誤,這表明將值重新分配給s會產生錯誤:

<ipython-input-37-7141eb599936> in c() 
     3   def c(): 
     4 #    nonlocal s     # fix 
----> 5    print(s) 
     6    while s: 
     7     s -= 1     # uncommenting raises UnboundLocalError 

UnboundLocalError: local variable 's' referenced before assignment 

最後,取消註釋nonlocal解決了此問題並提供了this post建議的所需輸出。

雖然問題解決了,但我想了解問題的根源。我注意到回溯點首次使用參數化參數s(例如print(s)),而不是指向實際導致錯誤的行(即while循環/分配)。

我懷疑在調用函數時,Python首先會建立本地作用域的賦值。然後,分配的優先級高於或覆蓋來自外部作用域的繼承變量。因此,如果沒有對s的分配,則使用外部s。相比之下,在賦值時,在函數調用中重新定義s,初始賦值之前的任何引用都會引發錯誤。這是正確的,還是有人可以解釋Python實際上在做什麼?

+0

也許你可以看看Python如何使用http://www.pythontutor.com線逐行執行文件! – Windmill

+0

@Windmill我很欣賞這個建議。他此刻,pythontutor顯示's'在'a()'的框架中可用,但它並不能清楚地表明在嵌套函數中's'是如何被觀察到的。 – pylang

回答

2

如果一個函數包含的變量(包括增強的分配,例如-=賦值,該變量是自動的地方,除非明確聲明爲global(或nonlocal)。如果沒有任務,它的自動全球,而不需要任何聲明(因爲在沒有任何值的情況下它幾乎不是一個局部變量)這種分析是在任何代碼生成之前執行的,所以你會遇到類似這樣的情況,其中後續代碼行可能會導致較早的代碼行一個錯誤

+0

這證實了我的懷疑。你是否知道這個支持這個的參考? – pylang

相關問題