如何在python中实现引用列表?

时间:2015-02-10 08:43:49

标签: python reference pass-by-reference

我正在尝试在python(2)中建模对象集合。该集合应通过列表界面创建可用对象的特定属性(整数,浮点或任何不可变对象)。

(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

我确信这是一个经常发生的情况,遗憾的是我无法找到关于如何在stackoverflow / google等上实现它的令人满意的答案。

在幕后,我希望将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

2 个答案:

答案 0 :(得分: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方法来让代理爱好者成为现实,但这足以满足您的使用需求。

答案 1 :(得分: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之类的东西来防止内存泄漏?