0

我正在处理其属性有时是列表的类,其元素可以是字典或具有属性的进一步嵌套对象等。我想执行一些切片,在我掌握 python 的情况下,只有在感觉非常非 Pythonic 的情况下才可行。

我的最小代码如下所示:

class X(object):
    def __init__(self):
       self.a = []

x=X()
x.a.append({'key1':'v1'})
x.a.append({'key1':'v2'})
x.a.append({'key1':'v3'})

# this works as desired
x.a[0]['key1'] # 'v1'

我想对嵌套字典中的键执行访问,但对包含该字典的列表的所有元素进行调用。执行此操作的标准 python 方式将是一个列表理解:

[v['key1'] for v in x.a]

但是,我的最小示例并不能完全传达我真实场景中嵌套的全部范围:a类中的属性列表X可能包含对象,其属性是对象,其属性是字典,我想在迭代时选择其键外部列表。

# I would like something like
useful_list = x.a[:]['key1'] # TypeError: list indices must be integers, not str
# or even better
cool_list = where(x.a[:]['key1'] == 'v2') # same TypeError

如果我开始理解每个有趣的键的列表,它很快看起来并不像 Pythonic。有没有一种很好的方法可以做到这一点,还是我必须为所有可能的列表和字典键配对编写“getter”方法?

更新:我一直在阅读有关重载列表的信息。显然,人们可能会弄乱getitem方法,该方法用于列表的索引和 dict 的键。也许是一个迭代列表成员的自定义类。这听起来开始做作...

4

1 回答 1

2

因此,您想要创建一个层次结构,其操作对不同类型意味着不同的事物,并且是递归定义的。多态性来拯救。

您可以覆盖__getitem__而不是我的get_items下面,但在您的情况下,最好定义一个非内置操作以避免冒歧义的风险。这真的取决于你。

class ItemsInterface(object):
    def get_items(self, key):
        raise NotImplementedError

class DictItems(ItemsInterface, dict):
    def __init__(self, *args, **kwargs):
        dict.__init__(self, *args, **kwargs)
    def get_items(self, key):
        res = self[key]
        # apply recursively
        try:
            res = res.get_items(key)
        except AttributeError:
            pass
        return res

class ListItems(ItemsInterface, list):
    def __init__(self, *args, **kwargs):
        list.__init__(self, *args, **kwargs)
    def get_items(self, key):
        return [ x.get_items(key) for x in self ]

x = ListItems()
x.append(DictItems({'key1':'v1'}))
x.append(DictItems({'key1':'v2'}))
x.append(DictItems({'key1':'v3'}))
y = DictItems({'key1':'v999'})
x.append(ListItems([ y ]))
x.get_items('key1')
=> ['v1', 'v2', 'v3', ['v999']]

当然,这个解决方案可能不是您所需要的(您没有解释如果缺少密钥等应该做什么),但您可以轻松修改它以满足您的需求。

ListItems此解决方案还支持DictItems. 该get_items操作以递归方式应用。

于 2013-03-10T07:08:15.070 回答