如何在 python 中实现引用列表?
How to implement a list of references in python?
我正在尝试为 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
我确信这是一种经常发生的情况,不幸的是我无法在 Whosebug / google 等上找到关于如何实现它的令人满意的答案
在幕后,我希望 object.attr
实现为可变对象。不知何故,我还希望该集合将 "list of references" 保存到 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
只需在中间添加另一个代理:
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
方法使代理更漂亮,但这对于您的用例来说已经足够了。
@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 这样的东西来防止内存泄漏?
我正在尝试为 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
我确信这是一种经常发生的情况,不幸的是我无法在 Whosebug / google 等上找到关于如何实现它的令人满意的答案
在幕后,我希望 object.attr
实现为可变对象。不知何故,我还希望该集合将 "list of references" 保存到 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
只需在中间添加另一个代理:
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
方法使代理更漂亮,但这对于您的用例来说已经足够了。
@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 这样的东西来防止内存泄漏?