Pythonic基于布尔参数构造数组的方法?

时间:2017-07-09 20:38:32

标签: python arrays boolean

我只是想知道pythonic代码如何解决这个问题:

假设你有一个功能:

def do_stuff(a=True, b=True, c=True, d=True):

在该函数中你想构造相应的对象:

elements = []
if a:
    elements.append(A())
if b:
    elements.append(B())
if c:
    elements.append(C())
if d:
    elements.append(D())

有没有更好的方法来编写这段代码?如果没有,可选参数不是“走的路”?

5 个答案:

答案 0 :(得分:1)

这个怎么样?

elements = [X() for x, X in ((a, A), (b, B), (c, C), (d, D)) if x]

但是你的整个方法看起来很奇怪。也许你不应该有这样的论点。但是不知道你真正需要什么......

答案 1 :(得分:1)

您可以使用itertools.compress

from itertools import compress

def do_stuff(a=True, b=True, c=True, d=True):
    elements = [val() for val in compress([A, B, C, D], [a,b,c,d])]

答案 2 :(得分:1)

  

有没有更好的方法来编写这段代码?

老实说,在我看来没有。你可以做一个聪明的黑客并使用它,但编写好的代码的目的是使其清晰易读,易于理解。除了你现在所拥有的以外,我认为所有其他方法都不符合要求。

当然看起来相当冗长,但最好是有一个冗长而不是不必要的复杂性。有时,显而易见的方法是最惯用,最强大,最干净,更“pythonic”的解决方案。在这种情况下,我认为最好做KISS。

但是,这还取决于您如何将参数传递给函数。你现在在做什么似乎有点奇怪。传入列表或字典可能更自然。

答案 3 :(得分:0)

这是一种相当干净的方式(也是可扩展的)方式:

class A: pass
class B: pass
class C: pass
class D: pass

def do_stuff(a=True, b=True, c=True, d=True):
    classes, args = (A, B, C, D), (a, b, c, d)
    elements = [classes[i]() for (i, arg) in enumerate(args) if arg]
    # Show results.
    print(list('class {} obj'.format(element.__class__.__name__) for element in elements))

do_stuff(1,1,1,1)  # -> ['class A obj', 'class B obj', 'class C obj', 'class D obj']
do_stuff(0,1,1,0)  # -> ['class B obj', 'class C obj']
do_stuff()         # -> ['class A obj', 'class B obj', 'class C obj', 'class D obj']
do_stuff(0,0)      # -> ['class C obj', 'class D obj']
do_stuff(b=False)  # -> ['class A obj', 'class C obj', 'class D obj']

注意我使用01代替FalseTrue,因为Python会将它们视为相同(它会考虑"真实性"非布尔值的值是否为0或空容器,具体取决于其类型)。

答案 4 :(得分:0)

您有许多需要根据条件调用的对象,if语句的重复是需要避免的:

objs = {True:A, True:B, True:C ,...}

def do_stuff(objs):
    return [obj() for key, obj in objs.items() if key]

无论这些可调用对象现在做什么,你只需调用它们,它们返回的任何内容都会被收集并保存在do_stuff返回的列表中。现在,未来扩展更容易,只需从objs字典中删除不需要的对象,或将其键设置为False,或者将其设置为布尔值为False的任何对象。