【问题标题】:Pythonic slicing of nested attributes嵌套属性的 Pythonic 切片
【发布时间】:2013-02-23 19:01:05
【问题描述】:

我正在处理属性有时是列表的类,其元素可以是字典或具有属性的进一步嵌套对象等。我想执行一些切片,根据我对 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]

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

# 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

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

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

【问题讨论】:

    标签: python list dictionary iterator slice


    【解决方案1】:

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

    您可以覆盖__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 操作是递归应用的。

    【讨论】:

    • 这完全符合预期。谢谢。由于使更改显式(通过新方法访问而不是重新定义 x['key1'] 所做的),它还具有更安全的感觉。不错
    猜你喜欢
    • 1970-01-01
    • 2017-10-12
    • 2011-07-17
    • 1970-01-01
    • 2020-08-24
    • 1970-01-01
    • 2010-09-17
    • 1970-01-01
    • 2014-03-25
    相关资源
    最近更新 更多