2011-07-30 44 views
1

這裏是一個片段:調用當地人()函數中的嵌套在一個類的方法

class Foo(object): 
    def bar(self, x): 
     def baz(y): 
      print locals()['self'] 
     .. 
     return baz(..) 

foo = Foo() 
foo.bar(..) 

我有2個框。在運行Python 2.5的Windows Vista上調用foo.bar(..)。在Ubuntu上,使用Python 2.7調用foo.bar(..)會拋出KeyError,但無法在locals()字典中找到self

任何想法?

編輯:我欠一個道歉;看起來我在試圖解決問題時誤導了你。在嵌套函數的實際代碼評估從DSL來的字符串:

  r = re.compile(r'\$(\w+)') 
      eval_string = r.sub(r'self.player.stats["\1"]', s) 
      result = eval(eval_string) 

它運行VISTA/Python 2.5的,無法在Ubuntu/Python 2.7版。

+1

這只是出於好奇,還是解決實際問題的一部分?如果它是真正的問題的一部分,我們可能會採取更好的方法來實現它,因爲你很少需要使用locals()。 –

+0

這段代碼不正確。調用foo.bar()實際上什麼都不做,因爲沒有任何返回,並且你沒有調用baz – joaquin

+0

@Jeremy:代碼僅用於演示目的。 – shanyu

回答

1

承認你可以計算變量字典跑壞之前,你可以這樣做:相反,如果你要計算在運行時(內bad)字典

class Foo(object): 
    def bar(self, x): 
     outer_locals = locals() 
     def baz(y): 
      print outer_locals['self'] 
     .. 
     return baz(..) 

,這是必經之路去:

import inspect 

def outer_locals(depth=0): 
    """ 
    With depth=0 behaves like locals(), depth=1 are the locals of the 
    containing frame, depth=2 the locals of the frame containing the containing 
    frame and so on... 
    """ 
    return inspect.getouterframes(inspect.currentframe())[depth+1][0].f_locals 

class Foo(object): 
    def bar(self, x): 
     def baz(y): 
      print outer_locals(1) 
     return baz(...) 

注意,如果在baz功能沒有被覆蓋,所有的bar當地人bad可供選擇:

class Foo(object): 
    def bar(self, x): 
     def baz(y): 
      print self 
     .. 
     return baz(..) 
+0

問題是我的代碼段只能在一種配置下工作,而不能在另一種配置下工作。 – shanyu

+0

@山雨:(我加了一個新的例子)你在說什麼配置?我測試了兩個提出的,他們的工作。也許你必須提供更多關於你的片段的上下文。 – GaretJax

+0

配置:Vista/Python2.5,Ubuntu/Python2.7。我的代碼片段不適用於後一種配置,你確定它可行嗎? – shanyu

0

嗯,我相信KeyError是正確的;我在OSX SnowLeopard上的Python 2.7.1上也得到了相同的結果。

這是爲什麼。我修改您的代碼如下:

class Foo(object): 

    def bar(self, x): 
     quux = 4 
     print locals() 

     def baz(y): 
      print locals()#['self'] 

     return baz(3) 

foo = Foo() 
foo.bar(2) 

,並得到

{'quux': 4, 'self': <__main__.Foo object at 0x1004945d0>, 'x': 2} 
{'y': 3} 

的問題是,在bazlocals字典應該包括self這是在外面的範圍界定。

我真的很困惑,爲什麼這發現selfbaz的位置在Windows下。它可能是2.5或Windows實現中的bug,或者語言規範在2.5和2.7之間更改。

1

我使用2.6.6獲得了您在2.7中報告的相同行爲。不過,我得到它使用2.5.2和2.4.6。 (所有的Linux)。

有趣的是:

>>> class Foo(object): 
    def bar(self, x): 
     def baz(y): 
      print self.__class__.__name__ 
      print locals()['self'] 
     return baz(4) 
... 
>>> Foo().bar(3) 
Foo 
<__main__.Foo object at 0x9801f4c> 
>>> 

大概有計算,其中僅在一個給定函數的範圍內實際使用的名稱添加到其表的局部符號表的過程中的一些優化或改造,即使給定的符號可訪問(並且不會是全局的!)它將被明確地引用。

將bar()的最後一行更改爲return baz(而不是return baz(4))我們可以看到self不是局部變量;這是一個自由變量:

>>> baz = Foo().bar(4) 
>>> baz.func_code.co_nlocals, f.func_code.co_varnames, f.func_code.co_freevars 
(1, ('y',), ('self',)) 

即使在這裏,不過,x並未被列入免費的變量之一,因爲when the name isn't used in the interior function, it doesn't count as free there

不過,這個解釋使得你在Vista上描述的行爲聽起來像是一個bug。

0

的局部變量總是當前調用的函數中定義的值,全局變量是總是在程序的頂部定義的值。 在barself是一個局部變量。在bazself位於本地和全局變量之間。你仍然可以參考它,因爲Python會在更高的範圍內搜索它,因爲它沒有在本地定義,但是 你無法訪問它的範圍字典。