2012-08-06 58 views
3

我有一個函數P()。致電load_variables()應該給P變量xload_variables應該能夠接受默認值作爲關鍵字參數。有意將變量放入調用者範圍的函數

這怎麼辦?

我曾嘗試以下:

import inspect 
def P(): 
    x = 1 
    load_variables(x = 2) 
    return x 

def load_variables(**kargs): 
    stack = inspect.stack() 
    try: 
     locals_ = stack[1][0].f_locals 
    finally: 
     del stack 
    for __k, __v in kargs.iteritems(): 
     locals_[__k] = __v 

print P() # => should print 2 

x = 1線不應實際在那裏,因爲我想load_variables()只是流血xP的範圍。

是否有另一種方法可能更好?我想要的是:

  1. 變量有一個默認值,例如, x = 2在上面的電話load_variables()
  2. 我可以覆蓋這些在load_variables,例如,load_varibales()有權訪問變量字典,如果x已經在這裏,我們覆蓋它,並且溢出這個x而不是給定的默認參數。

回答

1

Python編譯器和字節碼解釋器在可能的情況下將對局部變量的引用處理爲插入定義大小數組的插槽。這意味着如果局部變量未在範圍中初始化(分配給),那麼語言將不知道變量的一個槽位在範圍中,而是在封閉範圍或全局範圍中查找該變量。綜觀功能P的拆卸:

def P(): 
    load_variables(x=2) 
    return x 

dis.dis(P) 
    2   0 LOAD_GLOBAL    0 (load_variables) 
       3 LOAD_CONST    1 ('x') 
       6 LOAD_CONST    2 (2) 
       9 CALL_FUNCTION   256 
      12 POP_TOP    

    3   13 LOAD_GLOBAL    1 (x) 
      16 RETURN_VALUE   

你可以看到,如果沒有分配給x在局部範圍P將尋找它在全球範圍內。

要做到這一點是明確地說明你預期load_variables函數返回其變量正確的方法,用拆包:

x, y, z = load_variables(...) 
+0

我如何保證參數的順序與返回時相同?例如。如@Mohammad Ali寫道,'print load_variables(x = 2,y = 4,z = 10)'返回爲'{'y':4,'x':2,'z':10}' – 2012-08-06 09:31:10

+0

@ MadsOhmLarsen你必須將它們返回爲'return x,y,z'。 – ecatmur 2012-08-06 09:33:57

+0

關鍵字參數是一個字典,所以它不應該關心順序,這就是爲什麼我得到上面的混合回報。是否有可能獲得它們被輸入到'load_variables'的順序,以便我可以按照相同的順序返回未知數量的關鍵字參數? – 2012-08-06 09:55:15

1

更新:正如DSM指出的,不支持更新locals()。所以,答案是不正確的,至少對於CPython來說。

你能 load_variables()回報的字典,並使用 locals()更新本地變量:

def P(): 
    x=1 
    locals().update(load_variables(x=2)) 
    return x 

def load_variables(**kargs): 
    res={} 
    for __k, __v in kargs.iteritems(): 
     res[__k] = __v 
    return res 

注意 x=1規定或以其他方式 x將假設字節碼編譯器和你一個全局變量將得到 NameError例外 return x

如果你真的想擺脫 x=1你可以我們 retrun locals()['x']代替。

+1

不幸的是,這不起作用:您不能像[文檔警告](http://docs.python.org/library/functions.html#locals)這樣更新'locals'字典。由於實現相關的原因,'P'在CPython和PyPy中返回1,在IronPython中返回2。 – DSM 2012-08-06 09:28:33

+0

@DSM,我錯過了文檔中的那一點。謝謝。 – 2012-08-06 09:35:05

1

因爲我們正在談論的Python在這裏,有可能是一個辦法做到它,但我想知道:你應該嘗試嗎?

通常,更好的做法是定義一個共享的存儲/值對象,然後通過圍繞:

data = {} 

def P(data): 
    load_variables(data, x=2) 
    return data['x'] 

def load_variables(data, **kargs): 
    data.update(kargs) 

這樣的話,你會不會有不可預見的副作用。

+0

+1把「出血」的想法變成了一個更好的範圍似乎有點血腥 – msw 2012-08-06 12:19:10