4

我在一个真正的 Django 函数中有这段代码。如果满足某些条件,则将项目添加到list.

ret = []

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

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

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

return ret

它非常实用。你知道它的作用,那很好……
但我学会了欣赏它的美listdict理解力。

有没有一种更Pythonic的方式来表达这个结构,也许是一次性初始化和填充数组?

4

6 回答 6

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)()]

相关:当 else 完成得最多时,制作 if-elif-elif-else 语句的最有效方法是什么?

于 2013-11-07T09:11:02.057 回答
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),仍然具有评估所有值的讨厌的副作用,而且我不能真正将其视为一种改进我们已经开始了。

于 2013-11-07T09:11:11.783 回答
1

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

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

但同样,这只 适用于它调用检查的项目和方法具有相同名称的情况,即我的确切代码。它可以适应,但它有点硬。我对其他解决方案非常开放!

于 2013-11-07T09:06:24.177 回答
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 的映射字典答案。这里的主要区别是我建议只映射异常。

于 2013-11-07T09:31:13.093 回答
0

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

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

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

于 2013-11-07T09:39:25.273 回答
0

一种选择是使用“哨兵”样式的对象来代替不符合相应条件的列表条目。然后可以定义一个函数来过滤掉丢失的项目:

# "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
])
于 2019-03-01T07:24:53.463 回答