【问题标题】:Design patterns: Continue设计模式:继续
【发布时间】:2012-10-18 14:55:19
【问题描述】:

如果您将模式定义为一种巧妙的技巧,可以帮助您以一种优雅且可能更易读的方式解决编程问题[1]。使用continue 语句的设计模式是什么(如果要避免深度嵌套的if 语句)?

for item in items:
    if is_for_sale(item):
        cost=compute_cost(item)
        if cost<=wallet.money:
            buy(item)

for item in items:
    if not is_for_sale(item):
        continue
    cost = compute_cost(item)
    if cost > wallet.money:
        continue
    buy(item)

【问题讨论】:

  • 设计模式不是实现模式。所以不确定你在问什么。
  • continue 在其他语言中是一个非常常见的功能——我认为它在C 中也称为continue,在fortran 中称为cycle。我在 python 中并没有真正使用它(因为我还没有发现非常需要)
  • @mgilson -- 这就是我问这个问题的原因,似乎实际使用它的情况并不多(或者甚至应该使用它的地方)......跨度>

标签: python design-patterns refactoring


【解决方案1】:

这不是设计模式。但是当你有很多嵌套循环,并且不清楚那里发生了什么时,那就是代码异味。我建议在这里进行两次重构 - Extract MethodReplace Nested Conditional With Guard

首先,提取项目处理以显示您在做什么:

for(item in items)
   try_to_buy(item)

然后在新方法中应用警卫:

def try_to_buy(item):
   if not is_for_sale(item):
       return

   if compute_cost(item) > wallet.money:
       return

   buy(item)

【讨论】:

  • 我已将您的代码转换为 python。如果您不同意,请随时回滚。
  • @PaoloMoretti 不,没关系 :) 谢谢!
  • 我不知道它是什么重构方法(如果有的话),但我会将函数体更改为单个 if is_for_sale(item) and compute_cost(item) &lt;= wallet.money: buy(item) 以任何语言短路逻辑表达式。不需要continue 语句。
  • @martineau 这些语句是return 语句。代码的条件逻辑越少,越容易理解
  • 我认为多个 return 语句是一种代码异味,并且经常发现它们比包含单个 andif 语句更难理解。
【解决方案2】:

这有点偏离主题,但如果您正在寻找简化代码的方法,您可以这样做:

items_for_sale = (item for item in items if is_for_sale(item))
for item in items_for_sale:
    if compute_cost(item) <= wallet.money:
        buy(item)

就您最初的问题而言,如果continue 可以防止缩进多行,我只会使用它。如果您的 if 语句中只有一行,那么 continue 没有多大意义。

【讨论】:

  • 您在 items_for_sale 生成器中缺少一个右括号。
  • @Nathan Villaescusa -- 如果不确定它是否简化了代码(至少是可读性),对我来说,在示例中使用 contiunue 使代码更具可读性......
【解决方案3】:

我不知道你为什么说continue没有被大量使用,因为我至少在不满足条件时使用它来继续,而不是检查所有条件,这样代码是平坦的并且Flat is better than nested.

有时我使用异常来指示状态变化,并从深度嵌套的内部循环或函数中出来,例如

class MyException(Exception): pass

for item in items:
   try:
       for user in item.users:
           check_user(user)
   except MyException:
       continue

def check_user(user):
    if user.bad:
        raise MyException("bad user")

【讨论】:

  • @Anurag Uniyal -- +1,这正是我想要的。
猜你喜欢
  • 2011-01-19
  • 2019-07-20
  • 1970-01-01
  • 1970-01-01
  • 2010-12-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-04
相关资源
最近更新 更多