2012-11-14 89 views
2

請不要問我如何讓自己陷入這種情況。 可以說我有一個叫做ccollection的班級。打印類中的所有屬性

這個類具有以下屬性在運行時:

ccollection.a.b.x = 1 
ccollection.a.b.y = 3 
ccollection.a.b.z = 4 
... 
ccollection.a.c = 3 
ccollection.b = 3 

這個類將是設置動態地如上所述。所以沒有辦法事先了解課堂中的屬性。

現在我想打印的所有屬性在這個類,例如:

ccollection.a.b應打印

ccollection.a.b.x = 1 
ccollection.a.b.y = 3 
ccollection.a.b.z = 4 

ccollection.a應打印

ccollection.a.b.x = 1 
ccollection.a.b.y = 3 
ccollection.a.b.z = 4 
ccollection.a.c = 3 

我想你這個想法。每個打印應該開始打印同一級別和以下的所有元素。我正在尋找一種遞歸遍歷所有屬性的方法(這是一種樹狀數據結構)

+0

'collection.a'的類型是什麼?我問,因爲'collection.a.b'不是'collection'對象的屬性,而是'collection.a'的屬性。您可能需要使用自定義的'__str__'或'__repr__'方法創建幾個類,才能以您想要的方式工作。 – Blckknght

+0

@Blckknght,在ccollection.a.b.x = 1中,a本身是一個ccollection,b也是一個ccollection。 x設置爲1 – theAlse

+0

好的。你如何創建屬性。你只是直接分配它們(例如'ccollection.a = ccollection()')?或者是否有某種特定的方式讓給定的實例知道它應該具有的屬性?如果不是的話,你可以使用'dir',但是清除列表中包含的各種方法和其他方法將是一種痛苦。 – Blckknght

回答

1

這種情況確實需要重構。您正在使用不是作爲容器設計的對象。相反,使用一個容器,如字典或從字典繼承的類。


如果必須使用當前的設置,我同意,最有前途的方法似乎使用DIR Blckknght

class CCollection(object): 
    def get_children_strings(self): 
    list_of_strings = [] 
    for attr_name in dir(self): 
     if attr_name not in dir(CCollection()): 
     attr = getattr(self, attr_name) 
     if hasattr(attr, 'get_children_strings'): 
      list_of_strings.extend(["." + attr_name + child_string for child_string in attr.get_children_strings()]) 
     else: 
      list_of_strings.append("." + attr_name + " = " + str(attr)) 
    return list_of_strings 

    def print_tree(self, prefix): 
    print [prefix + s for s in self.get_children_strings()] 

然後你就可以

m = CCollection() 
m.a = CCollection() 
m.a.b = CCollection() 
m.a.b.x = 1 
m.a.b.y = 2 
m.a.c = 3 
m.d = 4 

m.print_tree("m") 
m.a.print_tree("m.a") 
m.a.b.print_tree("m.a.b") 

,並獲得輸出:

>>> m.print_tree("m") 
['m.a.b.x = 1', 'm.a.b.y = 2', 'm.a.c = 3', 'm.d = 4'] 
>>> m.a.print_tree("m.a") 
['m.a.b.x = 1', 'm.a.b.y = 2', 'm.a.c = 3'] 
>>> m.a.b.print_tree("m.a.b") 
['m.a.b.x = 1', 'm.a.b.y = 2'] 

藉此進一步,你可能會想要使用樹遍歷函數的類。如果您有一個獲取父節點的函數,一個無循環保證和一個保存該節點名稱的類變量,您可以自動生成當前通過prefix參數傳遞給print_tree函數的信息。

+0

我的老問題之一,但很好的答案。 – theAlse

0

看起來你想要一個像結構一樣的屬性訪問樹。這可以通過將dict進行子類化,然後設置適當的__getattr____setattr__以獲得所需的訪問API並同時打印所需。

也可以使用覆蓋__str__來使其完全按照您的要求打印。

編輯:

要快速描述這我會看起來像這樣。

class DictTree(object): 
    _children = {} 

    def __getattr__(self, name): 
     if not name in self._children: 
      self._children[name] = DictTree() 
     return self._children[name] 

    def __setattr__(self, name, v): 
     self._children[name] = v 

上述工程提供你想要的訪問和API接口,但在印刷時,我收到了RuntimeError: maximum recursion depth exceeded,因爲如何__getattr__工作。如果你調整了上面的代碼沒有這個問題,那麼它應該得到你想要的。該修復涉及__str__方法。

+0

我相信它可以這樣做(我不知道如何)。我正在尋找一種遞歸遍歷這種樹狀結構的方式。我可以順利遍歷樹,但是我總是失去上層的覆蓋__str__ – theAlse

+0

您應該從我所能看到的內容遞歸到樹中之前打印當前級別的值。 – sean

+0

由於所有DictTree對象都將使用相同的(單個)字典,因此您似乎不太可能將某個字典實例化爲類函數之外的_children類變量。請參閱,例如[This SO answer](http://stackoverflow.com/a/6021050/783037)。相反,你似乎想爲每個實例創建一個新的字典,例如'__init__'。不幸的是,由於'__setattr__'的改變,這很困難。 – beaslera