2012-12-10 67 views
1

我有這種情況下,我需要問一個嵌套類將附加項添加到外部類中的列表。繼承人僞代碼,這與我試圖做的相似。我將如何去實現它的工作?在嵌套類中,如何從Python中的嵌套類訪問外部類的元素?

class Outer(object): 
    outerlist = [] 
    class Inner(object): 
    def __call__(self, arg1): 
     outerlist.append(arg1) 

if __name__ == "__main__": 
    f = Outer() 
    f.Inner("apple") 
    f.Inner("orange") 

    print f.outerlist() 

這是我希望看到的 - apple, orange

詳情:
OS X,Python 2.7版

+4

爲什麼要使用一個嵌套類*在所有*? –

+0

因此,我試圖讓Outer類包含將接受參數的裝飾器,最好的方法是將裝飾器寫成類http://stackoverflow.com/questions/10610824/python-shortcut-for-writing- decorator-which-accept-arguments – sri

+2

是的,使用裝飾器的類是一個好主意,但這並不意味着你需要使用* nested *類。你想要解決什麼問題? –

回答

2

現在,我瞭解你的設計,你會發現一切都是錯誤的。

首先,Outer是一類;它沒有得到__call__版。你的第17行正要構造一個空的Outer對象,並且什麼也不做。如果你想「呼叫」對象,你可以定義一個__init__方法,或者,正如Sheena所建議的那樣,定義一個__new__並攔截初始化,因爲你實際上並不需要初始化對象。

老實說,我不認爲有人不明白__call__是如何工作的,但應該嘗試構建一些棘手的問題。但如果你堅持,請繼續閱讀。

這是一個非常奇怪的,也許是壞的設計,收集這種類的東西在類而不是一個實例。請記住,類變量實際上是全局變量,包含所有這些變量。如果你嘗試使用Outer或者從多個線程/事件處理程序/ greenlet /無論如何,這些使用將最終彼此跺腳。即使你認爲現在不會成爲問題,它可能會在未來某個時候。

您可以創建一個Outer實例,並將其成員用作裝飾器。例如:

from outer_library import Outer 

outer = Outer() 

@outer.get("/") 
… 

但我不確定那會好很多。這裏的整個設計似乎涉及在模塊級別執行操作,即使看起來您只是定義普通函數並在最後調用函數。你設法混淆自己的事實應該是這種設計有多混淆的證據。

但如果你想要做到這一點,你可能想要做的是定義Outer.__init__方法內的類,並將它們分配給實例成員。類是一流的值,可以像任何其他值一樣分配給變量。然後,使用這些類的__init__(或__new__)方法來完成你想要的工作,使這些類模擬函數。

這似乎令人困惑或誤導。但請記住,你所要做的全部事情就是以一種看起來像一種方法的方式使用一個類,這樣就會產生這種混淆。但是,如果你願意,你可以編寫裝飾器作爲函數(在這種情況下,作爲Outer的常規實例方法);它只是使問題的一個不同部分,而不是這部分。

設計類似這樣東西的一種更常見的方式是使Outer成爲一個完全正常的類,人們可以創建子類或創建實例,並提供一種明確的非奇妙方式來將處理函數方法或函數附加到URL。然後,一旦工作,設計一種方法來簡化處理程序註冊與裝飾器。

+0

採取了點。 (在''__main__''部分pastebin代碼是錯誤的 - 我的不好,)我不應該在網上討論我的項目atm,但可以說,它應該是一個singleton,應該可以調用,它是在我的代碼中正確實例化。對不起,關於不能說清楚的事情,下次我會繼續努力。但至少在我的問題得到回答之後。謝謝。 :) – sri

4

您只能使用完整全局名稱來訪問外部類:

class Outer(object): 
    outerlist = [] 
    class Inner(object): 
     def __call__(self, arg1): 
      Outer.outerlist.append(arg1) 

在python中,通常不需要在任何情況下嵌套類。有一些用例可以在函數中定義一個類(使用範圍變量),但很少需要嵌套類。

+0

這大部分都是正確的,但是使用'__call__'意味着你必須編寫'Outer.Inner()(「apple」)'而不是'Outer.Inner(「apple」)''。錯誤在於OP的代碼中,而不是你的代碼,但它仍然需要糾正。 – abarnert

+0

@abarnert:OP幾乎不知道需要實現什麼,所以我會推遲談論如何調用這個,直到它清楚真正的目標是什麼。 –

+0

@MartijnPieters對不起。我手中有一隻不安分的寵物 - 由於延誤,這涉及家庭作業 - 因此模糊。我在這個問題下回復了你的評論。請檢查。我會很樂意進一步解釋。謝謝。 – sri

2

這會得到想要的結果。

請注意使用__new__(A行)。這意味着,而不是適當地做任何施工的東西內部只是追加列表。此外,要訪問包含類的類屬性,只需使用外部類的名稱(B行)。

最後看到C行,列表不是函數。你原來的代碼中有一些額外的括號。

class Outer(object): 
    outerlist = [] 
    class Inner(object): 
     def __new__(self, arg1):    #A 
      Outer.outerlist.append(arg1)  #B 

f = Outer() 
f.Inner("apple") 
f.Inner("orange") 
print f.outerlist        #C 
+0

每次調用__init__或'__call__''時都調用__new__嗎?這很漂亮。 – sri

+0

@sri:不是每次它做一個'__call__' - 這是一個實例方法,可以多次調用。它被調用一次,當類需要創建一個實例時 - 通常是在'__init__'之前。 – abarnert

+1

@Sheena:他們是「類變量」。 「靜態」這個詞是指與類和實例都不相關的東西,而「屬性」是一種特殊的類變量,其描述符讓它們像一個實例變量一樣工作。但否則,所有的錢。 – abarnert

0

爲什麼不傳入外部類實例作爲內部類方法的參數?您可以通過這種方式訪問​​外部類實例的成員。

class Outer(object): 
    outerlist = [] 
    class Inner(object): 
     def __init__(self, outer_self): 
     self.outer = outer_self 
     def __call__(self, arg1): 
     self.outer.outerlist.append(arg1) 

if __name__ == "__main__": 
    f = Outer() 
    i = f.Inner(f) 
    i("apple") 
    i("orange") 

    print f.outerlist 
0

我認爲picmate指出的選項(通過外部類作爲內部輸入的輸入)是這個特定問題的一個好選擇。請注意,它也可以工作,而不必「嵌套」類(在我看來,由於它是不必要的,所以在這裏避免)。請注意,我還嵌入外一個內側的內部類的初始化(不嚴格需要這一步,但我在這裏包括它用於說明目的):

class Outer(object): 
    outerlist = [] 
    def __init__(self): 
    self.Inner=Inner(Outer=self) 
    def get_basket(self): 
    print "Outer basket: %s" %(self.outerlist) 

class Inner(object): 
    def __init__(self,Outer): 
    self.Outer=Outer 
    def __call__(self, arg1): 
    self.Outer.outerlist.append(arg1) 
    def get_basket(self): 
    print "Inner basket: %s" %(self.Outer.outerlist) 

if __name__ == "__main__": 
    f = Outer() 
    print "Initial state" 
    f.get_basket() 
    f.Inner.get_basket() 
    f.Inner("apple") 
    f.Inner("orange") 
    print "Final state" 
    f.get_basket() 
    f.Inner.get_basket()