【问题标题】:Avoid multiple IF to ensure Mccabe complexity避免多个 IF 以确保 McCabe 复杂性
【发布时间】:2018-10-17 08:01:52
【问题描述】:

我想问你对以下场景的不同观点:假设我们有几个列表,应该对那些不为空的列表执行一些操作:

if l1 or l2 or l3 or l4 or l5 or l6 or l7 or l8 or l9:

    print 'we have to do something in one or more lists'

    if l1:
        print 'l1'
        f1()

    if l2:
        print 'l2'
        f2()

    if l3:
        print 'l3'
        f3()

    if l4:
        print 'l4'
        f4()

    if l5:
        print 'l5'
        f5()

    if l6:
        print 'l6'
        f6()

    if l7:
        print 'l7'
        f7()

    if l8:
        print 'l8'
        f8()

    if l9:
        print 'l9'
        f9()

代码本身简单易懂,但这会为 Mccabe 复杂性带来 (12) 值。要降低此值,您将如何处理它?我非常愿意听听您的想法。

提前谢谢你。

更新:

想象正是这种具体情况。你怎么能接近它?:

    if a:
        A = True

    if b:
        B = True

    if c:
        C = True

    if d:
        D = "D"

    if e:
        E = "E"

    if f:
        F = "F"

我认为,在这种情况下,创建 6 个不同的函数效率不高,pythonic...

【问题讨论】:

  • 为什么还要顶if?其短路的好处可以忽略不计,在最坏的情况下(只有l9 不为空)此代码检查每个列表两次。
  • 嗨@DeepSpace,打印它存在的名单只是一个例子,在里面我必须做不同的事情,我要改变它
  • 这仍然不能回答为什么你需要if l1 or l2 or l3 or l4 or l5 or l6 or l7 or l8 or l9:
  • @Solar 为什么一样?它们有不同的值要附加到列表中。在接受的答案中,建议迭代条件和那些值。您还可以迭代条件和相应的函数。比如:conditions = [l1, l2, ...]; functions = [f1, f2, ...]; for condition, function in zip(conditions, functions): if condition: function()

标签: python algorithm if-statement cyclomatic-complexity


【解决方案1】:

使用列表列表和函数列表

def f1(l1):
   # do whatever is required to the  l1 list

def f2(l2):
   # similarly

# and similarly for f3 .. f9

...

lofl = [ l1, l2, l3, l4, l5, l6, l7, l8, l9 ]
loff = [ f1, f2, f3, f4, f5, f6, f7, f8, f9 ]

for f, l in zip( loff, lofl):
    if l:  # if the functions f cannot themselves safely do nothing for a falsy argument
        f( l) 

希望所需的函数数量少于九个(在此示例中)。您还可以轻松地向函数传递参数,因此函数可以是通用的,并在调用时告知要执行的变体操作

for f, l, p in zip( loff, lofl, lofp): # or, zip( loff, lofl, list(range(9)) )
    f(l, p)
    

或者实际上,甚至向函数传递任意一组关键字参数

lofargs=[ { 'foo':1, 'bar':'Monty' }, # kwargs for f1
          { 'foo':2, 'bar':'Python'}, 
          { 'foo':3 }, 
          {},                     # no kwargs at all for f4, 
          ...
        ]


for f, l, k in zip( loff, lofl, lofargs):
    f( l, **k )

几年后重新审视这一点,我现在将全力以赴地使用目录方法:

callstruct = [
          { 'func':f1, 'arg':l1, 'foo':1, 'bar':'Monty' },
          { 'func':f2, 'arg':l2, 'foo':2, 'bar':'Python'}, 
          { 'func':f3, 'arg':l3, 'foo':3 }, 
          { 'func':f4, 'arg':l4},                     # no kwargs at all for f4, 
          ... 
          ]

for d in callstruct:
    func = d.pop('func')
    arg = d.pop('arg')
    func( arg, **d)

如果有任何外部循环,请注意.pop 将改变callstruct 中的字典,因此您可能希望从dd = d.copy() 开始并处理dd。

不知道为什么我现在有这种感觉。也许过多的 JavaScript 暴露?我经常在我最近的代码中找到这样的单行代码。比许多ifs 更具可读性和可扩展性

 x = {'foo':1, 'bar':2, 'baz':3}.get(choice, DEFAULT) # or ERROR, or catch KeyError

【讨论】:

    【解决方案2】:

    如果将所有列表放在列表列表中:

    lol = [l1,l2,l3,l4,l5,l6,l7,l8,l9]
    

    然后你可以遍历列表列表:

    for l in lol:
        if l:
            # do something
    

    【讨论】:

    • @T Burgis 可能是一种有效的方法,但问题是我无法为所有列表执行相同的代码。所以在那种情况下,我必须提出更多的条件。
    • 你需要一个更复杂的数据结构来保存列表。也许是一本字典——键告诉你对列表做什么,值是列表的列表?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-09
    • 2013-04-30
    相关资源
    最近更新 更多