2009-08-27 70 views
2

我已經開始學習python,並且正在閱讀其他人編寫的腳本。我注意到,全局分散在整個腳本(我不喜歡它)..除此之外,我還注意到,當我有這樣python變量作用域

def some_function(): 
    foo.some_method() 
    # some other code 

if __name__ == '__main__' : 
    foo = Some_Object() 

    some_function() 

代碼,即使我不FOO進入some_function(),但some_function仍然可以操作foo(??!)。我不太喜歡這個,雖然它有點類似於Javascript關閉(?)。我想知道是否有可能阻止some_function()訪​​問foo,如果foo沒有作爲函數參數傳入?或者這是Python中的首選方式! (我使用python 2.5 ubuntu下頑強的時刻)

回答

4

該腳本有很嚴重的問題,風格和組織 - 例如,如果有人進口它,他們必須以某種神聖的事實,他們有叫some_function之前設置thescript.fooSome_Object實例... yeurgh! - )

不幸的是,你不得不從一個寫得很差的腳本學習Python,但我不確定我理解你的問題。 Python中的變量範圍是局部變量(包括參數),非局部變量(即周圍函數的局部變量,嵌套函數),全局變量,內建變量。

是你想要停止訪問全局變量? some_function.func_globals是隻讀的,但你可以做一個新的功能與空全局:

import new 
f=new.function(some_function.func_code, {}) 

現在呼籲f()會給出一個異常NameError: global name 'foo' is not defined。您可以設置此回模塊的名稱some_function,甚至做系統通過一個裝飾,例如:

def noglobal(f): 
    return new.function(f.func_code, {}) 
... 
@noglobal 
def some_function(): ... 

這將確保發生異常時some_function被調用。不過,我不清楚你期望從中得到什麼好處。也許你可以澄清...?

+0

剛剛完成刪除全局變量,我目前正在尋找nonlocals(周圍函數的本地 - 用於嵌套函數) 我想減少非本地使用的數量,可能是因爲我從PHP編碼帶來的習慣 - if一個變量不會被傳遞到一個函數中,那麼這個變量就不存在於函數中(IMO,如果不好的事情發生,它更容易調試) – Jeffrey04

+0

@Jeffrey,對於全局變量,但是非地址變量,特別是如果函數只是訪問它們並且不重新分配它們(後者實際上只是在2.6以後的版本中使用'nonlocal'關鍵字),這並不是一個真正的問題 - 而且我根據幾十年來的難得經驗進行講解;-)。 –

+0

@亞歷克斯感謝信息 – Jeffrey04

2

據我所知,從訪問foo停止some_function的唯一方法是消除some_function的範圍foo變量,可能像:

tmp = foo 
del foo 
some_function() 
foo = tmp 

當然,由於foo不再存在於some_function範圍內,所以會導致您的(當前)代碼崩潰。

在Python中,變量在本地搜索,然後在範圍內搜索直到全局變量,最後搜索內置插件。

另一種選擇可以是:

with some_object as foo: 
    some_function() 

但後來,你就必須至少聲明some_object.__exit__,也許some_object.__enter__爲好。最終結果是,您可以控制foosome_function的範圍內。

關於「with」語句的更多解釋here

+0

使用傳遞參數值取代全局變量始終是一個挑戰。似乎總是有一個更愚蠢的參考全球浮動。因此,在修復這個全局混亂時,重寫你的遺留全局變量,重寫你的函數來取代全局變量。那麼事情就會因爲正確的原因而破裂 –

1

在Python中,類似foo不是一個值,它是一個名稱。當你嘗試訪問它時,python會嘗試查找與之相關的值(如解引用指針)。它通過首先查看本地作用域(函數),然後向外工作直到它到達模塊作用域(即全局),並最終構建內部對象,直到找到與名稱匹配的內容爲止。

這使得像這樣的工作:

def foo(): 
    bar() 

def bar(): 
    pass 

儘管bar不存在,當你定義foo,該功能將工作,因爲你在後麪包圍foo一個範圍內定義bar

完全相同的事情發生在您發佈的代碼中,它只是fooSome_Object()的輸出,而不是函數定義。

正如亞歷克斯說的,事實上,你可以寫這樣的代碼並不意味着你應該

+0

現在的問題是...我不看我自己的代碼 – Jeffrey04