【问题标题】:Pythonic way of constructing an array based on boolean arguments?基于布尔参数构造数组的Pythonic方式?
【发布时间】:2017-12-13 12:35:59
【问题描述】:

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

假设你有一个函数:

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

有没有更优美的方式来编写这段代码?如果不是,可选参数可能不是“要走的路”?

【问题讨论】:

  • 是否有不希望用户传入elementslist 的原因?
  • 绝对有可能。虽然这只是一个哲学和美学问题。欢迎使用其他方法!
  • @LaimonasSutkus 问题是,什么是 A、B、C 和 D?
  • 抱歉不够具体。但目的是我在这里构造新对象。 A B C 和 D 是类。但是如果我要说 A B C 和 D 是方法,它会改变什么吗?
  • 用这些单独的参数来控制同一列表中元素的存在似乎有点不寻常。如果这些元素足够同质,可以在同一个列表中处理,我希望输入形式比单独的参数更统一;或者,ABCD 都是单独的类,将所有对象填充到同一个列表中可能没有意义。

标签: python arrays boolean


【解决方案1】:

有没有更优美的方式来编写这段代码?

说实话,在我看来没有。你可以做一个聪明的 hack 并使用它,但编写好的代码的目的是让它清晰易读,易于理解。除了你现在拥有的之外,我认为任何其他方法都不符合所有这些条件。

当然它看起来很冗长,但最好是冗长而不是不必要的复杂。有时,显而易见的方法是最惯用的、健壮的、干净的和“pythonic”的解决方案。在这种情况下,我认为最好做 KISS。

但是,这也取决于您将参数传递给函数的方式。你现在的所作所为似乎有点奇怪。传入列表或字典可能会更自然。

【讨论】:

    【解决方案2】:

    你可以使用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])]
    

    【讨论】:

    • @juanpa.arrivillaga 你是对的。有更好的方法来解决这个问题。我更新了答案:)
    【解决方案3】:

    这个怎么样?

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

    不过,您的整个方法看起来很奇怪。可能你不应该有这样的论点。但是在不知道您实际需要什么的情况下...

    【讨论】:

      【解决方案4】:

      您有许多对象需要根据条件调用,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 的任何对象。

      【讨论】:

        【解决方案5】:

        这是一种相当简洁(且可扩展)的方式:

        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 会以同样的方式对待它们(它通过它们是否为@ 来考虑非布尔值的“真实性”) 987654326@ 或空容器,具体取决于它们的类型)。

        【讨论】:

          猜你喜欢
          • 2010-11-10
          • 2020-03-23
          • 2015-05-14
          • 2017-11-29
          • 2021-05-21
          • 2015-01-27
          • 1970-01-01
          • 2022-01-03
          • 1970-01-01
          相关资源
          最近更新 更多