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

5
コンパイラーを使用してコードを整理することは危険なステップであり、間違いのないコンパイラーが必要です。あなたがあなたのコードにしたいことを知っているならもっと良いです!
Andrew

1
あなたがやっていることが仕様で定義されているなら、コンパイラを疑う理由はないと思います。それはあなたよりはるかに賢い人々によって書かれているでしょう、そしてあなたが彼らより間違いをした可能性ははるかに高いです。
意志

7
これは、意見に基づいてどのように閉じることができますか?2つの間にパフォーマンスの違いがないことを知ったの意見かもしれません。私はそうしなかったし、多くの人もそうしなかったと確信している。
Jorge Leitao

1
質問は非常に人気がありますが、特定の言語を頭に入れておかないと正確に回答することができません。
Emile Bergeron、2016年

回答:


195

returnステートメントは現在の関数の実行を終了するため、2つの形式は同等です(ただし、2番目の形式は最初の形式よりも間違いなく読みやすくなっています)。

両方の形式の効率は同等であり、ifいずれにしても条件がfalseの場合、基になるマシンコードはジャンプを実行する必要があります。

Pythonは、returnあなたのケースで1つのステートメントだけを使用できる構文をサポートしていることに注意してください:

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

32
Cもそれをサポートしています。return (A>B)?A+1:A-1;ただし、このようなコードを記述しても、パフォーマンスまったく向上ません。私たちが達成したことは、コードを難読化し、判読不能にし、場合によっては暗黙的な型の昇格に対して脆弱にすることです。
ランディン

47
@ランディンは難読化されていますか?読めない?三項演算子を知らない人のみ。
glglgl

6
@Lundinこの議論に続いて、予期しない結果が生じる<ので、悪い習慣-1 < 1uです。
glglgl

3
@glglgl:いいえ、人々は?:演算子がif-elseとして動作することを期待しているため、これは正しくありません。誰かがのようなコードを書くとしたら-1 < 1u、それは疑わしいですが、バグを簡単に見つけることができます。かなり多くの人が私が投稿したコードのいくつかのバージョンを書くでしょう。?:演算子を信頼できないほど、本番用コードでそのようなバグを頻繁に見ました。また、経験則として、同じことを行うために2つの異なる方法が言語で提供されている場合は、どちらか一方のみを使用し、気分に応じてどちらかをランダムに選択しないでください。
ランディン

6
@LundinはCで?:に注意するための引数ですが、Pythonにも適用されると言っているようです。Pythonで三項を使用すると予期しない結果が生じる例を指摘できますか?
lvc

33

以下からのクロムのスタイルガイド:

返品後は他の物を使わないでください:

# Bad
if (foo)
  return 1
else
  return 2

# Good
if (foo)
  return 1
return 2

return 1 if foo else 2

1
ありがとう。+1。返却後、他に使用しない理由を尋ねてもいいですか?
ティム

1
if-elseは機能的には同等ですが、詳細です。他は不要です。
skeller88 2017年

17
最初の方がより明確に見えるので驚きました。
Tim

4
あなたはどちらかのために合理的なケースを作ることができます。この決定で最も重要なことは、IMOがコードベース内で一貫していることです。
skeller88 2017年

2
ほとんどの場合、if-else-returnブランチがほとんど等しくないことがわかります(等しい場合は、とにかくリファクタリングする必要があります。switch構成を使用するか、Pythonの場合は、dictを列挙する/呼び出し可能オブジェクトを使用するなど)。したがって、ほとんどすべてif-else-returnがガード節のケースであり、それらは常になしでテスト可能です(テストされた式を模擬します)else
カウベルト2018年

5

コーディングスタイルについて:

言語に関係なく、ほとんどのコーディング標準は、単一の関数からの複数のreturnステートメントを悪い習慣として禁止しています。

(個人的には、複数のreturnステートメントが理にかなっている場合がいくつかあると思いますが、テキスト/データプロトコルパーサー、広範なエラー処理機能など​​)

これらすべての業界コーディング標準のコンセンサスは、式は次のように記述する必要があるということです。

int result;

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

効率について:

上記の例と問題の2つの例は、効率の点ですべて完全に同等です。これらすべての場合のマシンコードは、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に基づいて符号化規格では、私は「ルールを持っている機能は、関数の最後に、出口が1ポイントを持っていなければならない限り、出口が1ポイントはコードを作ります読みにくい」。つまり、MISRA-Cですが、ルールは例外です。返すことができる高度なパーサー関数を作成すると、たとえば10の異なるエラーが発生するため、ネストされた中括弧のレベルによってコードが完全に読み取れなくなります。このような場合、エラーが発生したときにすぐに返す方が賢明です。
ランディン

6
単一出口点の問題に関するディスカッションと詳細なディスカッションへのリンクについては、このSOの質問を参照してください。単一出口ルールが古風で過度に「エンジニアリング」であることに加えて、Pythonは特に「フラットはネストよりも優れている」ビューを促進しますreturn 。Pythonでそれを行うための慣用的な方法は、明確にどこにでも置くことです。
John Y

1
@percebus私は完全に同意し、サイクロマティックな複雑さは単一のリターンに対する良い議論です。そして、私はこれについてMISRA委員会を何度か突っ込んでいます。たとえば、これを参照してください。少なくともMISRA-C:2012でルールは勧告に格下げされました。
ランディン


2

インタプリタは気にしないので、これはスタイル(または好み)の問題です。個人的には、関数ベース以外のインデントレベルで値を返す関数の最後のステートメントを作成しないようにします。例1のelseは、関数の終わりがわずかな場合であっても覆い隠します。

好みで私は使用します:

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

これは、関数の最後のステートメントとして単一のreturnステートメントを使用するという優れた規則(前述のとおり)と、命令型の中間結果を回避するための優れた関数型プログラミングパラダイムの両方に従うためです。

より複雑な関数の場合は、可能であれば早すぎる戻りを避けるために、関数を複数のサブ関数に分割することを好みます。それ以外の場合は、rvalと呼ばれる命令型変数の使用に戻ります。関数が些細な場合や、終了前のreturnステートメントがエラーの結果でない限り、複数のreturnステートメントを使用しないようにしています。時期尚早に戻ると、先に進むことができないという事実が強調されます。複数のサブ関数に分岐するように設計された複雑な関数の場合、それらをcaseステートメント(たとえば、dictによって駆動される)としてコーディングしようとします。

一部のポスターは、操作の速度について言及しています。実行速度が必要な場合、Pythonは使用するのに最適な言語ではないため、実行速度は二次的なものです。私が重要なコーディング(つまり、エラーのないコードを書く)の効率としてPythonを使用しています。


1
ユーザーが私の回答に反対票を投じる場合、なぜ私が間違っていると思ったのかについてコメントをいただければ幸いです。
スティーブンエルウッド2017

読みやすさを考慮して、ステートメントごとに1行にするのは、たぶん前の行です。 var n = 1 if (A > B) else -1 return A+n
ペルセバス2017年

@percebus場合によっては、変数名が意味を強化できるかどうかに同意します。たとえば、 'code' move_x = 1 if my_x <opponent_x else -1#対戦相手に向かって移動
Stephen Ellwood

ところで私は実際にあなたの答えを支持しました。あなたが私の答えを見るとかなり似ています
パースバス2018年

2

個人的elseには可能な限りブロックを避けます。参照してくださいアンチ場合はキャンペーン

また、彼らはラインのために「余分な」料金を請求しません、あなたは知っています:p

「シンプルは複雑よりも優れている」と「読みやすさが重要」

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

2
なぜ反対票か。「pythonic」の答えです。あなたはそれを好ましい答えとは思わないかもしれません。しかし、無効なものではありません。私はまた、KISSの原則en.wikipedia.org/wiki/KISS_principleを
パースバス2018年

3
私はそれが読みやすさとシンプルさで得点するので、私はあなたの答えを賛成しました。私は個人的に、なぜ私の回答が積極的に否定的であるのかを教えられることなく、誰かが私に反対票を投じることを不快に感じます。
Stephen Ellwood

1
ifキャンペーンについて聞いたことはありませんが、ifが危険である理由を理解できました。私は常にifステートメントで囲まれたコードの量を制限し、dictを使用するようにelifツリーを書き直そうとします。しかし、これは少し話題から外れています。
Stephen Ellwood

1
@StephenEllwood dictsを使用してdiffを回避することは、パフォーマンスの点で非常に悪い考えです。
バッハウ

@Bachsauあなたはおそらく正しいです。すべてのスクリプトは数秒で実行されるので、パフォーマンスについて心配する必要はありませんでした。私にとって、読みやすさは通常、パフォーマンスよりも優れています。私はフルタイムのプログラマーではないので。それらは目的を達成するための手段にすぎません。
スティーブンエルウッド

1

バージョンAの方が簡単なので、バージョンAを使用します。

また、Javaですべてのコンパイラ警告をオンにすると、2番目のバージョンは不要であり、コードが複雑になるため警告が表示されます。


1

私は質問にpythonのタグが付いていることを知っていますが、それは動的言語について言及しているので、ルビでは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

これは、複数のリターンがないというスタイルの問題をかなりうまく回避します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.