2015-02-10 16 views
1

我想模擬python(2)中的對象的集合。該集合應該通過列表接口爲對象提供某個屬性(一個整數,浮點數或任何不可變的對象)。如何在python中實現引用列表?

(1)

>>> print (collection.attrs) 
[1, 5, 3] 
>>> collection.attrs = [4, 2, 3] 
>>> print (object0.attr == 4) 
True 

我特別期望集合中的這個列表界面,以允許重新分配一個單獨的對象的屬性,例如

(2)

>>> collection.attrs[2] = 8 
>>> print (object2.attr == 8) 
True 

我相信這是一個相當頻繁發生的情況下,遺憾的是我沒能找到如何實現它的計算器一個令人滿意的答案/谷歌等

在幕後,我預計object.attr將作爲一個可變對象來實現。不知何故,我也希望收藏品擁有object.attr的「參考列表」,而不是各自引用的(不可變的)值本身。

我問你的建議如何以優雅和靈活的方式解決這個問題。

的一種可能實現,它允許(1),但不用於(2)是

class Component(object): 
    """One of many components.""" 
    def __init__(self, attr): 
     self.attr = attr 

class System(object): 
    """One System object contains and manages many Component instances. 
    System is the main interface to adjusting the components. 
    """ 
    def __init__(self, attr_list): 
     self._components = [] 
     for attr in attr_list: 
      new = Component(attr) 
      self._components.append(new) 

    @property 
    def attrs(self): 
     # !!! this breaks (2): 
     return [component.attr for component in self._components] 
    @attrs.setter 
    def attrs(self, new_attrs): 
     for component, new_attr in zip(self._components, new_attrs): 
      component.attr = new_attr 

的!!!換行符(2),因爲我們創建了一個新列表,其條目是對所有Component.attr的值的引用,而不是對屬性本身的引用。

感謝您的輸入。

TheXMA

+1

要做到這一點,你可以使'System._components'成爲一個自定義類,它實現了你想要的__setitem__行爲。 – jonrsharpe 2015-02-10 08:51:50

+0

完美,就像@filmor在下面做的一樣。 – TheXMA 2015-02-10 09:53:04

回答

2

只需添加另一個代理其間:

class _ListProxy: 
    def __init__(self, system): 
     self._system = system 

    def __getitem__(self, index): 
     return self._system._components[index].attr 

    def __setitem__(self, index, value): 
     self._system._components[index].attr = value 


class System: 
    ... 
    @property 
    def attrs(self): 
     return _ListProxy(self) 

可以使代理通過實現所有其他list方法發燒友,但這足以爲您的使用情況。

+0

完美,這有很大幫助!我在下面的答案中試圖使它更普遍一些。 – TheXMA 2015-02-10 09:43:38

0

@filmor非常感謝您的回答,這完美地解決了問題!我做了一些更一般的:

class _ListProxy(object): 
    """Is a list of object attributes. Accessing _ListProxy entries 
    evaluates the object attributes each time it is accessed, 
    i.e. this list "proxies" the object attributes. 
    """ 
    def __init__(self, list_of_objects, attr_name): 
     """Provide a list of object instances and a name of a commonly 
     shared attribute that should be proxied by this _ListProxy 
     instance. 
     """ 
     self._list_of_objects = list_of_objects 
     self._attr_name = attr_name 

    def __getitem__(self, index): 
     return getattr(self._list_of_objects[index], self._attr_name) 

    def __setitem__(self, index, value): 
     setattr(self._list_of_objects[index], self._attr_name, value) 

    def __repr__(self): 
     return repr(list(self)) 

    def __len__(self): 
     return len(self._list_of_objects) 

是否有任何重要的列表方法丟失?

如果我想要一些組件(對象)被垃圾收集? 我是否需要使用類似WeakList的內容來防止內存泄漏?

+0

回答我的後一個問題:不,list_of_objects的彈出元素也改變了System中的列表,它們都是對同一列表的引用。 – TheXMA 2015-02-10 09:51:58

+0

我忘了實現'__len__',否則我認爲所有重要的列表方法都應該在這些適應的魔法方法之上工作。 – TheXMA 2015-02-11 09:44:13