简体   繁体   English

编写此筛选列表理解的最pythonic方法是什么?

[英]What's the most pythonic way to write this filtered list comprehension?

Maybe i'm just up too late. 也许我太晚了。

I have an object that is a thin wrapper around a dictionary. 我有一个对象是字典周围的薄包装器。 It will pretend to have a property for any key in the dictionary, and return None if a nonexistent key is referenced. 它会伪装成字典中任何键的属性,如果引用了不存在的键,则返回None。

I want to get back only the unique, "truthy" values for three possible keys. 我想只找回三个可能的键的唯一“truthy”值。 (not None). (不是没有)。 the object may not have one or more of the keys. 对象可能没有一个或多个键。 Or, it may have the same value in two or three of the keys. 或者,它可以在两个或三个键中具有相同的值。

This code does what I want: 这段代码做我想要的:

set(getattr(obj, field) for field in ['field1', 'field2', 'field3'] if getattr(obj, field))

I just don't like the look of repeating getattr() twice. 我只是不喜欢两次重复getattr()的样子。 I feel like i'm overlooking an obviously better way to do this. 我觉得我忽略了一个明显更好的方法来做到这一点。

You could filter out the None values afterwards: 您可以在之后过滤掉None值:

set(filter(bool, [getattr(obj, field) for field in ['field1', 'field2', 'field3']]))

Or you could just forget about the object. 或者你可以忘记对象。 This is probably the way I would do it: 这可能是我这样做的方式:

a_dict = {'key1': 1, 'key2': 2, 'key3missing': 3}

print set([a_dict[key] for key in ['key1','key2','key3'] if key in a_dict])

# prints: set([1, 2])

If your thin wrapper returns default None : 如果您的瘦包装器返回默认值None

s = set(getattr(obj, field) for field in ['field1', 'field2', 'field3']) - {None}

another possibility: 另一种可能性

s = set(filter(None, (getattr(obj, field) for field in ['field1', 'field2', 'field3']))

another take on using the getattr default: 另一个使用getattr默认值:

set(x for x in getattr(obj, field, None) for field in ['field1', 'field2', 'field3'] if x)

edit: 编辑:

here is to show you the logic behind this function - and to show why i think it might be better than some of the other solutions (i could be wrong - but hey - life is all about learning from mistakes) 这里是为了向您展示这个功能背后的逻辑 - 并说明为什么我认为它可能比其他一些解决方案更好(我可能是错的 - 但是嘿 - 生活就是从错误中学习)

obj = Your_Object
fields = ['field1', 'field2', 'field3']

def get_set(obj, fields):
    result = []
    for field in fields:
        x = getattr(obj, field, None)
        if x:
            result.append(x)
    return set(result)

as you can see, there is only 1 loop, and getattr() is only called once for each field. 正如您所看到的,只有一个循环,并且getattr()仅针对每个字段调用一次。 and only "truthy" values are added to the result. 并且只有“truthy”值被添加​​到结果中。 i think this is a bit more efficient than getting all the results, and then removing the "non-truthy" values later. 我认为这比获得所有结果更有效,然后在以后删除“非真实”值。 but please correct me if i am wrong. 但如果我错了,请纠正我。 cheers. 干杯。

Something like: 就像是:

from operator import attrgetter

class DictWrapper(object):
    def __init__(self, d):
        self.d = d

    def __repr__(self):
        return repr(self.d)

    def __getattr__(self, name):
        return self.d.get(name)

    def truthy(self, *keys):
        values = attrgetter(*keys)(self)
        if not isinstance(values, tuple):
            values = (values,)
        return filter(None, set(values))

dw = DictWrapper({'x': 3, 'y': None, 'z': 'zebra'})
dw.truthy('x', 'y' ,'z', 'bob')
# [3, 'zebra']
dw.truthy('x')
# [3]
dw.truthy('y')
# []

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM