2009-09-20 24 views
11

locals是一個內置的函數,它返回一個本地值的字典。該文件說:在Python中修改當地人

警告

這本字典的內容應 不能修改; 的變化可能不會影響解釋器使用的局部變量 的值。

不幸的是,exec在Python 3.0中有相同的問題。這有什麼辦法嗎?

使用案例

考慮:

@depends("a", "b", "c", "d", "e", "f") 
def test(): 
    put_into_locals(test.dependencies) 

取決於存儲在一個列表test.dependences在它的參數提供的字符串。這些字符串是字典d中的鍵。我希望能夠寫出put_into_locals,這樣我們就可以從d中提取出這些值並將它們放入當地人。這可能嗎?

+0

鏈接到相關文檔:https://docs.python.org/2/library/functions.html#locals – 2014-12-05 19:53:25

+0

爲什麼'測試。依賴關係= [「a」,「b」,「c」,「d」,「e」,「f」]'工作,然後將我上面寫到你的'test()'函數中的任務裝飾起來? – 2017-06-22 22:34:54

+0

你是否設法更新/修改當地人或不? – 2017-10-16 22:20:32

回答

11

我剛剛測試過exec,它在Python 2.6中起作用。2

>>> def test(): 
...  exec "a = 5" 
...  print a 
... 
>>> test() 
5 

如果您使用的是Python 3.x,它將不再工作,因爲在運行時本地語言被優化爲數組,而不是使用字典。

當Python檢測到「exec語句」時,它將強制Python將本地存儲從數組切換到字典。然而,由於「exec」是Python 3.x中的一個函數,編譯器無法做出區分,因爲用戶可能已經完成了諸如「exec = 123」之類的操作。

http://bugs.python.org/issue4831

要修改功能的當地人對 飛也不是沒有可能 幾個後果:通常情況下, 功能當地人不存儲在一個 字典,而是一個數組,其 指數是在已知語言環境的編譯時間 處確定的。這至少與 exec增加的新當地人衝突 。老exec語句 規避這一點,因爲 編譯器知道,如果沒有 全局/當地人ARGS一個exec發生在 功能,該命名空間是 「未優化」,即不使用 當地人陣列。由於exec()現在是一個 正常函數,所以編譯器不知道 知道什麼「exec」可能被綁定到,因此 是不能被特別處理的。

+0

我認爲這是相當確定的,這是不可能的 – Casebash 2009-09-20 05:35:27

+1

@Casebash,它可能是,它只需要字節碼黑客或Python 2。x – Unknown 2009-09-20 05:49:27

+0

好的,我現在不會解決這個問題 – Casebash 2009-09-20 06:37:29

-1

我不知道它是否受到同樣的限制,但你可以得到一個直接引用當前幀(並從那裏,局部變量字典)通過檢查模塊:

>>> import inspect 
>>> inspect.currentframe().f_locals['foo'] = 'bar' 
>>> dir() 
['__builtins__', '__doc__', '__name__', '__package__', 'foo', 'inspect'] 
>>> foo 
'bar' 
+7

這與當地人()完全一樣; 'inspect.currentframe()。f_locals是locals()'是true。 – 2009-09-20 04:21:38

+1

這不是**完全**錯誤,但它只適用於框架是最頂層的,即全局範圍。它不會在本地範圍內工作。 – bendtherules 2015-06-12 01:50:30

3

這是不可能的。我認爲這是爲了稍後進行性能優化。 Python字節碼通過索引而不是名稱引用本地文件;如果locals()需要可寫,它可能會阻止解釋器執行一些優化,或使其更加困難。

我相當肯定你不會找到任何核心API來保證你可以像這樣編輯當地人,因爲如果這個API可以做到的話,locals()也不會有這個限制。

不要忘記,所有的本地人必須在編譯時存在;如果你引用一個在編譯時沒有綁定到本地的名字,編譯器會認爲它是全局的。編譯後不能「創建」當地人。

請參閱this question以獲得一種可能的解決方案,但這是一種嚴重的黑客攻擊,您確實不想這樣做。

注意,有一個基本的問題,您的示例代碼:

@depends("a", "b", "c", "d", "e", "f") 
def test(): 
    put_into_locals(test.dependencies) 

"test.dependencies"是不是指「f.dependencies」,其中f是當前功能;它引用了實際的全球價值「測試」。這意味着如果你使用一個以上的裝飾:

@memoize 
@depends("a", "b", "c", "d", "e", "f") 
def test(): 
    put_into_locals(test.dependencies) 

將不會再工作,因爲「測試」是memoize的真實包裝的函數,而不是依賴的。 Python 真的需要一種方法來引用「當前正在執行的函數」(和類)。

5

局部變量由賦值語句修改。

如果你有字典鍵是字符串,請不要使它們成爲局部變量 - 只要使用它們作爲字典鍵。

如果你絕對必須有本地變量做到這一點。

def aFunction(a, b, c, d, e, f): 
    # use a, b, c, d, e and f as local variables 

aFunction(**someDictWithKeys_a_b_c_d_e_f) 

這會從你的字典中填充一些局部變量而不做任何神奇的事情。

+0

正是我想的;你也可以動態地創建一個函數;見幫助(types.FunctionType) – gatoatigrado 2009-10-04 23:34:27

+4

這是一個有趣的想法。但是,有許多應用程序中字典實際上包含許多其他變量('aFunction()'不需要),它使得'aFunction()'的當前定義中斷。一個有用的概括是:'aFunction(a,b,c,d,e,f,** kwargs)'。 – EOL 2010-07-18 10:40:59

+0

@EOL:額外的參數變量使函數中斷?這很難想象。一些額外的變量應該是 - 好 - 只是變量。因爲一些額外的變量而中斷的函數具有非常差的設計。修復這個功能會更好。 – 2010-07-18 12:01:27

1

我將它存儲在一個變量:

refs = locals() 
def set_pets(): 
    global refs 
    animals = ('dog', 'cat', 'fish', 'fox', 'monkey') 
    for i in range(len(animals)): 
     refs['pet_0%s' % i] = animals[i] 

set_pets() 
refs['pet_05']='bird' 
print(pet_00, pet_02, pet_04, pet_01, pet_03, pet_05) 
>> dog fish monkey cat fox bird 

如果你想要把它在當地人()之前測試你的字典:

def set_pets(): 
    global refs 
    sandbox = {} 
    animals = ('dog', 'cat', 'fish', 'fox', 'monkey') 
    for i in range(len(animals)): 
     sandbox['pet_0%s' % i] = animals[i] 
    # Test sandboxed dict here 
    refs.update(sandbox) 

的Python 3.6.1在MacOS塞拉利昂