【问题标题】:Pythonic way to use the second condition in list comprehensions在列表推导中使用第二个条件的 Pythonic 方式
【发布时间】:2017-08-14 11:22:11
【问题描述】:

让我们假设以下函数:

def myfun(my_list, n, par1=''):
    if par1 == '':
        new_list = [[my_fun2(i,j) for j in range(n)] for i in range(n)]
    else:
        new_list = [[my_fun2(i,j) for j in range(n)] for i in range(n) if my_fun2(i,n) == par1]
    return new_list

如您所见,根据par1,有两种不同的情况。我不喜欢第 3 行和第 5 行几乎相同,并且不遵循 DRY(不要重复自己)原则。如何改进这段代码?

【问题讨论】:

  • 检查我的答案,我没有你的确切功能,所以很难在相同的环境中测试它,但我认为它应该可以解决问题
  • 很高兴了解您实际尝试解决的问题。

标签: python if-statement list-comprehension


【解决方案1】:

这可能有效:

new_list = [[my_fun2(i,j) for j in range(n)] for i in range(n) if par1 == '' or my_fun2(i,n) == par1]

所以这样使用:

def myfun(my_list, n, par1=''):
    return [
               [my_fun2(i,j) for j in range(n)]
               for i in range(n) if par1 == '' or my_fun2(i,n) == par1
           ]

【讨论】:

  • 您也可以将返回合并到第 2 行,但这取决于您自己
  • 尽管这是一个可能的解决方案,但我认为可读性不是很好,所以它缺少python禅宗的“可读性计数”规则。恕我直言,级联列表理解应该分开。
  • 次要注意:您不需要在推导式(或括号内)内使用反斜杠 :)
  • 谢谢!这正是我需要的。事实证明,它比列表推导更像是一个逻辑运算符问题:) 请注意,如果 n 很大,那么解决方案就不是很好,因为我们在每一步都检查 par1 == ''。跨度>
【解决方案2】:

您可以通过使用在第一种情况下仅返回 True 的函数以及在第二种情况下实际将 my_fun2 结果与 par1 进行比较的函数来动态选择条件函数:

def myfun(my_list, n, par1=''):
    if par1 == '':
        cond = lambda x, y: True
    else:
        cond = lambda i, n: my_fun2(i, n) == par1
    return [[my_fun2(i,j) for j in range(n)] for i in range(n) if cond(i,n)]

或者在par1不是空字符串的情况下将外部循环替换为generator expression

def myfun(my_list, n, par1=''):
    if par1 == '':
        outer = range(n)
    else:
        # a conditional generator expression
        outer = (i for i in range(n) if my_fun2(i,n) == par1)
    return [[my_fun2(i,j) for j in range(n)] for i in outer]

但是,不要让 DRY 使函数更难阅读、维护或调试。我个人认为你的方法很好(而且可能更快),你可能不应该改变任何东西。

【讨论】:

  • 谢谢,是的,我同意。 DRY 和可读性之间只有一线之隔。
  • @Trarbish 好吧,这也是一个关于性能的问题(不仅仅是关于可读性)。您的方法将比我的生成器表达式方法更快(这可能是这里提到的最快的非 DRY 方法)。
【解决方案3】:

为什么不使用过滤器?

from operator import eq
def myfun(my_list, n, par1=''):
    new_list = ([my_fun2(i,j) for j in range(n)] for i in range(n))
    if par1 != '':
        new_list = filter(eq(par1),new_list)
    return list(new_list)

【讨论】:

  • 我知道对于未来和 Python3,列表推导是一种更好的方式来替代使用 map、filter 和 reduce。
  • python 3 中的过滤器创建了一个生成器,这就是为什么返回值被 list() 包围的原因
猜你喜欢
  • 2017-01-08
  • 1970-01-01
  • 1970-01-01
  • 2017-12-23
  • 2017-12-15
  • 1970-01-01
  • 1970-01-01
  • 2020-04-07
  • 2015-10-04
相关资源
最近更新 更多