使用if-return-return或if-else-return更有效吗?


141

假设我有一个if带有的语句return。从效率的角度来看,我应该使用

if(A > B):
    return A+1
return A-1

要么

if(A > B):
    return A+1
else:
    return A-1

使用编译语言(C)或脚本化语言(Python)时,我应该选择一种还是另一种?


11
使用编译语言,您不必担心效率。编译器将其整理出来。您应该编写代码以便可以阅读。(您仍然需要担心算法的效率,而草率使用类型等会影响效率-您只是不必过多担心样式。)尽管我对Python并不了解。
ams 2012年

5
依靠编译器整理代码是一个危险的步骤-并需要一个可靠的编译器。如果您知道Whay Tou希望您的代码可以做的更好!
安德鲁

1
如果您在做什么是由规范定义的,那么我认为没有任何理由怀疑编译器。人们可能会比你聪明得多,而且犯错的可能性也比他们大得多。

7
如何封闭基于意见的观点?您知道两者之间没有性能差异之后,可能会有一种看法。我没有,而且我很确定很多人也没有。
豪尔赫·雷涛

1
虽然这个问题很受欢迎,但如果没有特定语言的提示就无法准确回答,否则,每种语言的回答对于这种格式来说都太长了。
Emile Bergeron

Answers:


195

由于该return语句终止了当前函数的执行,因此两种形式是等效的(尽管第二种形式比第一种更具可读性)。

两种形式的效率都相当,如果if条件为假,则基础机器代码必须执行跳转。

请注意,Python支持一种语法,该语法仅允许您使用一种return情况:

return A+1 if A > B else A-1

32
C也支持。return (A>B)?A+1:A-1;但是,这样编写代码绝对不会提高性能。我们所获得的一切就是使代码变得混乱,不可读,并且在某些情况下更容易受到隐式类型提升的影响。
伦丁

47
@Lundin感到困惑?看不懂?仅适用于不了解三元运算符的用户。
glglgl 2012年

6
@Lundin遵循此论点<是不明智的做法,因为-1 < 1u会产生意外结果。
glglgl 2012年

3
@glglgl:否,因为人们期望?:运算符的行为像if-else一样,这是不正确的。如果有人编写类似的代码-1 < 1u,我对此表示怀疑,那么他们很容易发现该错误。但是,很多人会写一些我发布的代码版本。我在生产代码中经常看到这样的错误,以至于无法信任?:运算符。根据经验,如果该语言为您提供两种不同的方式来做相同的事情,则仅使用其中一种,不要根据自己的心情随机选择这两种方式中的任何一种。
伦丁

6
@Lundin是在C语言中谨慎使用?:的参数,但您似乎在说它也适用于Python。您能否指出在Python中使用三进制会导致意外结果的任何示例?
lvc 2012年

33

根据Chromium的风格指南:

返回后请勿使用其他:

# Bad
if (foo)
  return 1
else
  return 2

# Good
if (foo)
  return 1
return 2

return 1 if foo else 2

1
谢谢。+1。请问退货后为什么不使用其他商品?
蒂姆(Tim)

1
if-else在功能上等效,但是很冗长。其他是不必要的。
skeller88

17
我很惊讶,因为第一个看起来更清晰,因此更好。
蒂姆(Tim)

4
您可以为任何一个提供合理的理由。IMO决定中最重要的是在代码库中保持一致。
skeller88

2
在大多数情况下,您可能会发现if-else-return分支几乎永远不相等(如果分支相等,那么无论如何您都应该重构;使用switch构造或Python,枚举dict /使用callable /等)。因此,几乎所有if-else-return情况都是保护子句,并且总是可测试的(模拟被测试的表达式)而没有else
Cowbert

5

关于编码风格:

无论哪种语言,大多数编码标准都禁止从单个函数中使用多个返回语句,这是一种不好的做法。

(尽管我个人会说在某些情况下多个返回语句确实有意义:文本/数据协议解析器,具有大量错误处理的功能等)

所有这些行业编码标准的共识是,该表达式应写为:

int result;

if(A > B)
{
  result = A+1;
}
else
{
  result = A-1;
}
return result;

关于效率:

上面的示例和问题中的两个示例在效率方面都完全等效。在所有这些情况下,机器码都必须比较A> B,然后跳转到A + 1或A-1计算,然后将结果存储在CPU寄存器或堆栈中。

编辑:

资料来源:

  • MISRA-C:2004规则14.7,依次引用...:
  • IEC 61508-3。第3部分,表B.9。
  • IEC 61508-7。C.2.9。

37
您确定单回教徒感染了大多数编码标准吗?那将是可怕的。
丹尼尔·菲舍尔

7
我会说规则在大多数情况下都没有意义。我倾向于发现代码更易读,更容易在适当的时候返回。但这就是我。但是,我想到的是针对每个公司/项目的编码标准,而不是像MISRA这样的东西,否则,愚蠢的处方有时可能会有一些优点。我希望大多数人不接受单一出口点的想法。
丹尼尔·菲舍尔

3
@DanielFischer:在我为公司设计的基于MISRA的C编码标准中,我有一条规则:“一个函数在函数的末尾只能有一个退出点,除非有一个退出点使代码成为可能。可读性差”。因此是MISRA-C,但有一个例外。如果您编写了一个高级解析器函数,该函数可以返回10个不同的错误,则嵌套花括号的级别使代码完全不可读-在这种情况下,遇到错误时立即返回更明智。
伦丁2012年

6
请参阅此SO问题进行讨论,并进一步链接到有关单出口问题的进一步讨论。除了过时且过分“工程化”的单出口规则外,Python还专门提倡“扁平优于嵌套”视图,并且在return 任何明确的地方放上代码都是Python的惯用方式。
约翰Y

1
@percebus我完全同意,圈复杂性是反对单收益的一个很好的论据。而且我已经多次向MISRA委员会征询意见,例如,请参见this。至少该规则在MISRA-C:2012中降级为咨询。
隆丁

3

对于任何明智的编译器,您都应该观察到没有区别。它们应该被编译为相同的机器代码,因为它们是等效的。


2

因为口译员不在乎,所以这是一个风格(或偏好)问题。就我个人而言,我尽量不要对以函数基础以外的缩进级别返回值的函数做最终声明。示例1中的else会(即使只是稍微)掩盖了函数的结束位置。

根据偏好,我使用:

return A+1 if (A > B) else A-1

因为它遵循了将单个return语句作为函数中的最后一条语句的良好约定(如已提到的那样)以及避免命令式中间结果的良好的函数编程范例。

对于更复杂的功能,我更喜欢将功能分解为多个子功能,以避免可能的过早返回。否则,我将恢复使用称为rval的命令式样式变量。我尽量不要使用多个return语句,除非该函数是微不足道的,或者在结束之前的return语句是由于错误导致的。过早返回会突出显示您无法继续前进的事实。对于旨在分解为多个子功能的复杂功能,我尝试将它们编码为case语句(例如,由dict驱动)。

一些海报提到了运行速度。对于我来说,运行时的速度是次要的,因为如果您需要执行速度,那么Python并不是最好的语言。我将Python用作对我很重要的编码效率(即编写无错误代码)。


1
如果用户要拒绝我的回答,我将对他们为什么认为我错了发表意见。
斯蒂芬·艾尔伍德(Steven Ellwood)

为了便于阅读,我可能只需要一行就可以使每个语句1行。 var n = 1 if (A > B) else -1 return A+n
percebus

在某些情况下,@ percebus我同意变量名是否可以增强含义。例如:如果my_x <对手_x否则-1#向对手移动,则'code'move_x = 1
斯蒂芬·埃尔伍德

顺便说一句,我实际上赞成你的回答。如果您看到我的答案很相似
percebus

2

我个人else尽可能避免阻塞。参见反假宣传运动

另外,他们不收取“额外”费用,你知道:p

“简单胜于复杂”和“可读性为王”

delta = 1 if (A > B) else -1
return A + delta

2
为什么要投反对票?是一个“ pythonic”答案。您可能不认为这是首选的答案。但不是无效的。我也遵循KISS原则en.wikipedia.org/wiki/KISS_principle
percebus '18

3
我支持您的回答,因为对我而言,它的可读性和简单性得分很高。我个人觉得冒犯别人是对我投下反对票,却没有教育我为什么我的回答是积极的否定。
斯蒂芬·艾尔伍德

1
之前没有听说过反if运动,但是可以理解为什么ifs会很危险。我总是尝试限制if语句包含的代码量,并尝试重写elif树以使用dict。但是,这有点偏离主题了。
Stephen Ellwood '18

1
@StephenEllwood使用dicts来避免差异是一个非常糟糕的主意。
巴绍(Bachsau)

@Bachsau你可能是对的。由于我所有的脚本都在几秒钟内运行,因此我从来不必担心性能。对我而言,可读性通常胜过性能。由于我不是专职程序员,它们只是达到目的的一种手段。
斯蒂芬·艾尔伍德

1

版本A更简单,这就是我要使用它的原因。

而且,如果您打开Java中的所有编译器警告,您将在第二个版本上收到警告,因为它是不必要的,并且增加了代码复杂度。


1

我知道这个问题被标记为python,但是它提到了动态语言,因此我想我应该提到在ruby中if语句实际上具有一个返回类型,因此您可以执行以下操作

def foo
  rv = if (A > B)
         A+1
       else
         A-1
       end
  return rv 
end

或者因为它也有隐式的回报

def foo 
  if (A>B)
    A+1
  else 
    A-1
  end
end

解决了没有很好的多次收益的样式问题。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.