是否有“Pythonic”方法创建带有条件项的列表?

时间:2013-11-07 09:06:24

标签: python list-comprehension

我在真正的Django函数中得到了这段代码。如果符合某些条件,则会将项目添加到list

ret = []

if self.taken():
    ret.append('taken')

if self.suggested():
    ret.append('suggested')

#.... many more conditions and appends...

return ret

非常功能。你知道它做了什么,那很好...... 但我学会了欣赏listdict理解的美丽。

是否有更多的 Pythonic 方法来表达这个结构,也许是一次性初始化并填充数组?

6 个答案:

答案 0 :(得分:3)

创建一个映射字典:

self.map_dict = {'taken': self.taken,
                 'suggested': self.suggested,
                 'foo' : self.bar}
[x for x in ['taken', 'suggested', 'foo'] if self.map_dict.get(x, lambda:False)()]

相关:Most efficient way of making an if-elif-elif-else statement when the else is done the most?

答案 1 :(得分:2)

没有太大的改进,但我会提到它:

def populate():
    if self.taken():
        yield 'taken'
    if self.suggested():
        yield 'suggested'

ret = list(populate())

我们可以做得更好吗?我持怀疑态度。显然,需要使用另一种语法而不是列表文字,因为我们不再有“结果中的1表达式= 1元素”不变。


编辑:

我们的数据有一个模式,它是(条件,值)对的列表。我们可能会尝试使用它来利用它:

[value
 for condition, value
 in [(self.taken(), 'taken'),
     (self.suggested(), 'suggested')]
 if condition]

但是这仍然是对你如何描述你的逻辑的一个限制,无论条件如何(除非你投入大量的lambda),仍然有评估所有值的令人讨厌的副作用,我不能真正看到它比我们开始时的改进。

答案 2 :(得分:1)

对于这个非常具体的示例,我可以这样做:

return [x for x in ['taken', 'suggested', ...] if getattr(self, x)()]

但同样,这个在它调用的项目和方法检查时具有相同的名称,即我的确切代码。它可以调整,但它有点硬皮。我对其他解决方案非常开放!

答案 3 :(得分:1)

我不知道为什么我们要附加与函数名称匹配的字符串,但如果这是一般模式,我们可以使用它。函数具有__name__属性,我认为它总是包含您在列表中的内容。

那怎么样:

return [fn.__name__ for fn in (self.taken, self.suggested, foo, bar, baz) if fn()]

如果我正确理解了这个问题,那么非成员函数和成员函数一样。

编辑:

好的,我们添加一个映射字典。并将函数名称拆分为元组或列表。

fns_to_check = (self.taken, self.suggested, foo, bar, baz)

# This holds only the exceptions; if a function isn't in here,
# we will use the .__name__ attribute.
fn_name_map = {foo:'alternate', bar:'other'}

def fn_name(fn):
    """Return name from exceptions map, or .__name__ if not in map"""
    return fn_name_map.get(fn, fn.__name__)

return [fn_name(fn) for fn in fns_to_check if fn()]

您也可以使用@ hcwhsa的映射字典答案。这里的主要区别是我建议只映射异常。

答案 4 :(得分:0)

在另一个实例中(其中一个值将被定义但可能是None - 在我的情况下是一个Django模型的字段),我发现只需添加它们并过滤工作:

return filter(None, [self.user, self.partner])

如果其中任何一个是None,它们将从列表中删除。它比仅仅检查更加密集,但是在不写书的情况下仍然可以非常简单地清理输出。

答案 5 :(得分:0)

一个选择是拥有一个“哨兵”风格的对象来代替失败相应条件的列表条目。然后可以定义一个函数,以filter删除丢失的项目:

# "sentinel indicating a list element that should be skipped
Skip = object()

def drop_missing(itr):
    """returns an iterator yielding all but Skip objects from the given itr"""
    return filter(lambda v: v is not Skip, itr)

借助这种简单的机制,我们可以相当接近列表理解样式的语法:

return drop_skips([
    'taken' if self.taken else Skip,
    'suggested' if self.suggested else Skip,
    100 if self.full else Skip,
    // many other values and conditions
])