2017-10-04 50 views
2

我想了解Python(3.x)中的變量作用域,但下面是一個不起作用的代碼示例,我不知道爲什麼。不帶參數輸入的函數變量範圍

def function_a(A): 
    function_b() 

def function_b(): 
    print(A) 

function_a(1) 

導致NameError: name 'A' is not defined

所以,我認爲它的工作方式是,function_a()function_b()是definid。之後,我運行function_a(),其中A被賦值爲1.

因此在function_a()的範圍內存在變量A = 1。

然後function_b()被調用並打算打印變量A的值。 A不存在於function_b()的作用域中。因此,我認爲它會看起來更高,這將是function_a()的範圍,因爲function_b()function_a()內運行。

但很明顯,我錯了。究竟發生了什麼?

+2

雖然它不是_directly_有關這個問題,我懷疑你會發現這篇文章有幫助:關於Python的名稱和值事實與神話(http://nedbatchelder.com/text/names.html) ,這是由SO老將Ned Batchelder寫的。 –

回答

6

只是因爲你有叫function_bfunction_a內並不意味着我t會繼承function_a的範圍,並有充分的理由。該函數從它定義的地方獲取範圍,而不是它被調用的地方。

如果您想完成類似closures的操作,您應該嘗試在function_a的內部定義function_b

def function_a(A): 
    def function_b(): 
     print(A) 

就這樣說,我並沒有真正看到這裏的封閉用例。您最好將變量作爲參數傳遞。這樣它會更加可重用和可測試。

def function_a(A): 
    function_b(A) 

def function_b(A): 
    print(A) 
3

因此,我希望它看起來級別更高,因爲function_b()是內 function_a()

它看起來更高版本上運行這將是function_a()的 範圍。但function_a的範圍不高於function_b的範圍。範圍有些獨立。不要將範圍層次與堆棧框架混淆。層次結構中的下一個範圍是模塊範圍,這裏是全局範圍; A不在全球範圍內。

要訪問function_b中的A,您可以將其作爲參數傳遞給function_b或在模塊範圍中定義A

+1

Upvoted,但我認爲你應該考慮用一種對新手更容易理解的方式來描述它 - IMO在這裏有太多技術術語(「範圍層級」,「堆棧框架」),當你可以表達相同的通過說「像函數的作用域取決於它的位置_defined_,而不是它被調用的位置」這樣一種更清晰的方式。 –

+0

@Rawing感謝您的反饋。我想這就是接受的答案,而且很可能是爲什麼它被接受。學習...... –

+0

作爲提問者,我可以證實這確實是我接受@ hspandher的答案的原因。我也提出了你的回答,因爲它確實回答了這個問題。我只是認爲另一個答案說得更清楚一些,說'函數從定義的範圍獲取範圍,而不是它被調用的地方'。 感謝您的回答,雖然 – elevendollar

1

會發生什麼事是,在function_b,在全球範圍內的搜索完,因爲全球範圍內沒有定義名稱A和沒有封閉的功能範圍存在,你會得到一個NameError

如果一個封閉的範圍存在:

def function_a(A): 
    def function_b(): 
     print(A) 
    function_b() 
function_a(1) # prints 1 

或全局名稱A定義:

A = 2 
def function_a(A): 
    function_b() 

def function_b(): 
    print(A) 

function_a(1) # prints 2 (finds global name A) 

你會得到的A因爲查找將成功打印的結果。

0

我假設發生這種情況是因爲python沒有將綁定參數放置在變量綁定接收的同一個命名空間中。參數綁定僅存在於函數的範圍內。

正確的方法實現的是使用python關閉您的影響(其包圍他們的父母函數的命名空間):

def function_a(A): 
    def function_b(): 
     print(A) 

    function_b() 

function_a(1) 

您可能值A簡單地傳遞給這兩種功能,但這可能會建議你做含A類(特別是如果A是由許多功能要求):

class A(object): 
    def __init___(self, a): 
     self.a = a 

    def function_a(self): 
     self.function_b() 

    def function_b(self): 
     print(self.a) 

foo = A(1) 
foo.function_a()