2013-01-04 48 views
1

考慮下面的代碼:如何確定哪些名稱空間對Python堆棧框架可見?

GLOBAL_VARIABLE = 1 

def someFunction(): 
    nonLocalVariable = 2 

    def anotherFunction(): 
     localVariable = 3 

     class LocalClass(object): 
      __metaclass__ = MyMetaClass 
      __customCode = """ 
        GLOBAL_VARIABLE + nonLocalVariable + localVariable 
       """ 

    anotherFunction() 

someFunction() 

我的MyMetaClass實現者,超常類生成 方法基礎上,__customCode屬性的內容的類。 __customCode 可以包含Python表達式,所以我想確保在__customCode中提到的變量名稱 引用與在普通Python方法中定義的相同變量名稱 相同的對象。

當元類被調用時,它會傳遞一個包含 這個類的內容的字典,這意味着它知道__customCode,但這沒什麼幫助。 如果使用,則會得到執行語句的棧幀,即anotherFunction()。該堆棧幀 有.f_locals屬性(含localVariable)和(含GLOBAL_VARIABLE,除其他事項外)一.f_globals 屬性,但是這兩個 在一起不告訴整個故事。

鑑於anotherFunction()堆棧幀(或其他任何東西能搶我持有的 從MyMetaClass裏面執行),我怎麼能發現 命名空間,其中nonLocalVariable的生活,和任何其他的命名空間嵌套 全球之間本地命名空間?

我目前使用的Python 2.7,但如果答案是不同的Python 3.x, 這也是很好的知道。

+0

@SamueleMattiuzzo:你的編輯不正確;代碼是正確的嵌套,這是*這個問題的重點*。 –

+0

@MartijnPieters cheers martijn,我試着閱讀整個問題,以瞭解他/她是否打算縮進它,或者只是一個間距錯誤:) –

回答

4

除了locals()globals()結構,編譯器在指向當地人在嵌套函數細胞的形式添加上「自由變量」信息,對於任何本地變量,它是一個)不被分配給,並且b )指的是一個作用域變量(Python 3.x增加了nonlocal關鍵字,允許你分配這樣一個變量,就像關鍵字global一樣)。

在你的具體情況下,有沒有這樣的變量。您的嵌套代碼都不是指nonLocalVariable;僅當anotherFunctionLocalClass實際使用該變量時,python編譯器(因此在字節編譯時)會添加必要的結構以便能夠從範圍中提取nonLocalVariable

下面是一個例子嵌套設置:

>>> def foo(x): 
...  y = None 
...  def bar(): 
...   return x 
...  return bar 
... 
>>> bar = foo('spam') 
>>> foo.__code__.co_cellvars 
('x',) 
>>> bar.__code__.co_freevars 
('x',) 
>>> dir(bar.func_closure[0]) 
['__class__', '__cmp__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'cell_contents'] 
>>> bar.func_closure[0].cell_contents 
'spam' 

注意如何fooco_cellvars列表codeobject列出x和codeobject爲bar已經xco_freevars上市; y而不是因爲bar從未使用過。對bar函數的引用具有func_closure結構,該結構保存x當前值,如bar創建時的範圍所給出的。代碼對象保存一個函數的字節碼;它們是在編譯時創建的。 func_closure元組是在運行時基於freevarscellvars結構創建的。

因爲這發生在編譯時,動態創建對這樣的範圍變量的引用最多是棘手的。就我個人而言,在這種情況下,我甚至不願意支持使用範圍變量。

+0

我知道解釋器必須有一些*關於包含名稱空間的信息,但我沒有意識到它是由編譯器完成的。這種感覺很糟糕,但是Python似乎總體上對這種元編程充滿敵意,所以我並不感到驚訝。不過,這只是一個角落案例,所以我會按照你的建議完全按照你的建議去做,而忽略它。謝謝(你的)信息! – Screwtape

+0

@Screwtape:您可以使用作用域變量創建包裝函數,並返回嵌套函數;如果它使用任何範圍變量,則生成的代碼對象至少會擁有正確的信息。然後你所要做的就是附加正確的範圍信息('func_closure'信息)......好玩!但是你必須以某種方式強制編譯器列出嵌套作用域中的任何*和*所有本地變量以供單元使用。不容易。 –