您能在python中轻松创建一个类似列表的对象,该对象的项使用类似描述符的东西吗?
我正在尝试编写一个抽象另一个接口的接口 底部接口在要求什么方面有些不一致:有时是id,有时是名称。我试图隐藏这些细节 我想创建一个类似列表的对象,允许您向其中添加名称,但在内部存储与这些名称关联的id 最好是,我想为类属性使用类似描述符的东西,只是它们可以处理列表项。也就是说,调用一个函数(如您能在python中轻松创建一个类似列表的对象,该对象的项使用类似描述符的东西吗?,python,python-2.7,Python,Python 2.7,我正在尝试编写一个抽象另一个接口的接口 底部接口在要求什么方面有些不一致:有时是id,有时是名称。我试图隐藏这些细节 我想创建一个类似列表的对象,允许您向其中添加名称,但在内部存储与这些名称关联的id 最好是,我想为类属性使用类似描述符的东西,只是它们可以处理列表项。也就是说,调用一个函数(如\uuuu get\uuu)将添加到列表中的所有内容转换为我希望在内部存储的id,并调用另一个函数(如\uu set\uuu)在尝试从列表中检索项目时返回对象(提供方便的方法),而不是实际id 这样我就可以
\uuuu get\uuu
)将添加到列表中的所有内容转换为我希望在内部存储的id,并调用另一个函数(如\uu set\uuu
)在尝试从列表中检索项目时返回对象(提供方便的方法),而不是实际id
这样我就可以做这样的事情:
def get_thing_id_from_name(name):
# assume that this is more complicated
return other_api.get_id_from_name_or_whatever(name)
class Thing(object)
def __init__(self, thing_id):
self.id = thing_id
self.name = other_api.get_name_somehow(id)
def __eq__(self, other):
if isinstance(other, basestring):
return self.name == other
if isinstance(other, Thing):
return self.thing_id == other.thing_id
return NotImplemented
tl = ThingList()
tl.append('thing_one')
tl.append('thing_two')
tl[1] = 'thing_three'
print tl[0].id
print tl[0] == 'thing_one'
print tl[1] == Thing(3)
文档建议为一个行为类似于可变序列的对象定义17个方法(不包括构造函数)。我不认为子类化list
对我有任何帮助。感觉上,我应该能够做到这一点,只是在某个地方定义了一个getter和setter
UserList
显然被贬低了(虽然是在python3中?但我使用的是2.7)
有没有一种方法可以实现这一点或类似的功能,而不必重新定义太多的功能?您不需要覆盖所有的列表方法--\uuuu setitem\uuuuuuuuuu、\uuuuuu init\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu和\append应该足够了--您可能还需要插入和其他一些方法。您可以编写uuu setitem和uuu getitem来调用单独的“Thing”类上的uuu set和uuu get方法,就像描述符一样 下面是一个简短的示例-可能类似于您想要的:
class Thing(object):
def __init__(self, thing):
self.value = thing
self.name = str(thing)
id = property(lambda s: id(s))
#...
def __repr__(self):
return "I am a %s" %self.name
class ThingList(list):
def __init__(self, items):
for item in items:
self.append(item)
def append(self, value):
list.append(self, Thing(value))
def __setitem__(self, index, value):
list.__setitem__(self, index, Thing(value))
例如:
>>> a = ThingList(range(3))
>>> a.append("three")
>>> a
[I am a 0, I am a 1, I am a 2, I am a three]
>>> a[0].id
35242896
>>>
--编辑--
O.p.评论道:“我真的希望有一种方法可以拥有列表的所有功能——添加、扩展、切片等,只需重新定义get/set项行为。” 因此,我们必须以这种方式覆盖所有相关的方法。但是,如果我们想要避免的只是大量的锅炉板代码,而许多函数的作用几乎相同,那么可以动态生成新的重写方法——我们只需要一个装饰器,将普通对象更改为
对象
,用于所有设置值的操作:
class Thing(object):
# Prevents duplicating the wrapping of objects:
def __new__(cls, thing):
if isinstance(thing, cls):
return thing
return object.__new__(cls, thing)
def __init__(self, thing):
self.value = thing
self.name = str(thing)
id = property(lambda s: id(s))
#...
def __repr__(self):
return "I am a %s" %self.name
def converter(func, cardinality=1):
def new_func(*args):
# Pick the last item in the argument list, which
# for all item setter methods on a list is the one
# which actually contains the values
if cardinality == 1:
args = args[:-1] + (Thing(args[-1] ),)
else:
args = args[:-1] + ([Thing(item) for item in args[-1]],)
return func(*args)
new_func.func_name = func.__name__
return new_func
my_list_dict = {}
for single_setter in ("__setitem__", "append", "insert"):
my_list_dict[single_setter] = converter(getattr(list, single_setter), cardinality=1)
for many_setter in ("__setslice__", "__add__", "__iadd__", "__init__", "extend"):
my_list_dict[many_setter] = converter(getattr(list, many_setter), cardinality="many")
MyList = type("MyList", (list,), my_list_dict)
它是这样工作的:
>>> a = MyList()
>>> a
[]
>>> a.append(5)
>>> a
[I am a 5]
>>> a + [2,3,4]
[I am a 5, I am a 2, I am a 3, I am a 4]
>>> a.extend(range(4))
>>> a
[I am a 5, I am a 0, I am a 1, I am a 2, I am a 3]
>>> a[1:2] = range(10,12)
>>> a
[I am a 5, I am a 10, I am a 11, I am a 1, I am a 2, I am a 3]
>>>
我不明白为什么子类化
list
对您没有帮助。如果我了解您的要求,您需要重新实施\uuuuu init\uuuuuuuuuu
,\uuuuuuuu setitem\uuuuuuuu
和append
,似乎您可以使用东西而不是名称ThingList与普通列表有什么不同?您可能想看看NamedTuples
的纯Python实现方法,该方法听起来至少表面上类似于您可能想要做的事情,如createnamedList
——但你的问题对我来说并不完全清楚。@JochenRitzel ThingList是不同的,因为我可以将字符串放入其中,但我可以从中获取Thing对象。@RicardoCárdenes子类化list意味着我有方法的列表定义,所以我没有重写的方法将以不一致的方式工作;tl.append('foo')和tl.extend(['foo'])看起来应该做同样的事情,但不会。我真的希望有一种方法可以拥有列表中的所有功能-添加、扩展、切片等,只需重新定义get/set项行为。好的,这非常令人印象深刻。