すべての分岐が実行される複数の条件ステートメントを持つ関数がある場合、関数から戻ります。複数のifステートメント、またはif/Elif/elseを使用する必要がありますか?たとえば、次の関数があるとします。
def example(x):
if x > 0:
return 'positive'
if x < 0:
return 'negative'
return 'zero'
書く方が良いですか:
def example(x):
if x > 0:
return 'positive'
Elif x < 0:
return 'negative'
else:
return 'zero'
どちらも同じ結果になりますが、一方がもう一方よりも効率的であるか、またはより慣用的であると考えられていますか?
編集:
最初の例では、ifステートメントは常に評価されますが、私にはそうではないようです。
たとえば、コードを実行すると:
l = [1,2,3]
def test(a):
if a > 0:
return a
if a > 2:
l.append(4)
test(5)
lは[1,2,3]のままです。
コメントを回答に拡張します。
すべてのケースが戻る場合、これらは実際に同等です。それらの中から選択する際に重要になるのは、それから、より読みやすいものです。
後者の例では、Elif
構造体を使用して、ケースが暗黙的に戻り値であるという事実に依存するのではなく、ケースが相互に排他的であることを明示的に述べています。これにより、その情報がより明確になり、コードが読みやすくなり、エラーが発生しにくくなります。
たとえば、別のケースがあると誰かが判断したとします。
def example(x):
if x > 0:
return 'positive'
if x == -15:
print("special case!")
if x < 0:
return 'negative'
return 'zero'
突然、ユーザーがそのケースを相互に排他的にすることを意図した場合、潜在的なバグがあります(明らかに、これは例ではあまり意味がありませんが、より現実的なケースでは可能性があります)。 Elif
sが使用され、コードを追加するときに見ている可能性が高いレベルでコードを追加する人に動作が表示される場合、このあいまいさが取り除かれます。
最初のコード例に出くわした場合、if
ではなくelifs
sを使用するという選択は、ケースがnotとは相互に排他的であることを暗示していると思います。したがって、x
の値を変更するなどの方法を使用して、どのif
sを実行するかを変更できます(明らかにこの場合、意図は明白であり、相互に排他的ですが、ここでも、あまり明確でないケースについて話しています-一貫性は良いので、簡単な例でも明らかな場合は、一方向に固執するのが最善です)。
違いを理解するためにこれをチェックしてください:
>>> a = 2
>>> if a > 1: a = a+1
...
>>> if a > 2: a = a+1
...
>>> a
4
versus
>>> a = 2
>>> if a > 1: a = a+1
... Elif a > 2: a = a+1
...
>>> a
3
最初のケースは、空のif
ステートメントを含む2つの異なるelse
に相当します(またはelse: pass
); 2番目のケースでは、Elif
は最初のif
ステートメントの一部です。
場合によっては、正しいセマンティクスのためにElif
が必要です。これは、条件が相互に排他的でない場合です。
if x == 0: result = 0
Elif y == 0: result = None
else: result = x / y
インタプリタがすべての条件をチェックする必要がないため、場合によっては効率的です。これは、例の場合です。 xが負の場合、なぜ正のケースをチェックするのですか?この場合のElif
は、単一の分岐のみが実行されることを明確に示すため、コードを読みやすくします。
一般に(例:例)、常に_if..Elif
_ラダーを使用して、条件が相互に排他的であることを明示的に示します。あいまいさ、バグなどを防ぎます。
Elif
を使用せず、代わりにif
を使用する可能性があると考えることができる唯一の理由は、前のif
ステートメント(または以前のElif
ステートメント)は、相互に排他的ではなくなる可能性があるように条件を変更した可能性があります。つまり、実際にははしごではなく、連結されたif(..Elif..else)
ブロックを分離するだけです。 (スタイルを整えて、誰かが誤ってそれをElif
であると考えて '修正'する必要があると思わないようにするために、個別のブロックの間に空白行を残します)
ここで、要点を証明するための、不自然な例を示します。
_if total_cost>=10:
if give_shopper_a_random_discount():
print 'You have won a discount'
total_cost -= discount
candidate_prime = True
if total_cost<10:
print 'Spend more than $10 to enter our draw for a random discount'
_
最初のifブロックが割引を適用する場合、両方の条件に達する可能性があることがわかります。そのため、2番目のifブロックも実行します。これは、元の合計が10以上だったため混乱するメッセージを出力します。
ここでElif
を使用すると、このシナリオを防ぐことができます。しかし、そのシナリオであっても、2番目のブロックを実行したい他のシナリオが存在する可能性があります。
_if total_cost<10:
<some other action we should always take regardless of original undiscounted total_cost>
_
Elif
の方が少し効率的で、非常に論理的です。if
sを使用すると、プログラムは毎回各論理式を評価する必要があります。 Elif
sでは、常にそうであるとは限りません。ただし、あなたの例では、x > 0
の評価が最も安価な操作の1つであるため、この改善は非常に小さく、おそらく気づかないでしょう。
Elif
sを使用する場合は、最適な順序を考えることもお勧めします。この例を考えてみましょう:
if (x-3)**3+(x+1)**2-6*x+4 > 0:
#do something 1
Elif x < 0:
#do something 2
ここでは、プログラムは毎回醜い表現を評価する必要があります!ただし、順序を変更した場合:
if x < 0:
#do something 2
Elif (x-3)**3+(x+1)**2-6*x+4 > 0:
#do something 1
プログラムは最初にx <0(安価で単純)かどうかをチェックし、そうでない場合にのみ、より複雑な式を評価します(ところで、このコードはあまり意味がなく、単なるランダムな例です)。
また、パーリアルが言ったこと。
あなたが言ったときのあなたの質問のeditの部分について:「最初の例では、ifステートメントは常に評価されるので、私には当てはまらないようです。 」
そして、あなたはこの例を提供しました:
l = [1,2,3]
def test(a):
if a > 0:
return a
if a > 2:
l.append(4)
test(5)
はい、確かにリストl
は[1,2,3]
この場合、return
ステートメントが関数の終了につながり、Elif
を使用した場合と同じ結果になるため、ブロックを実行した結果を返すだけです。 returnステートメントを使用します。
次に、print
の代わりにreturn
ステートメントを使用してみます。2番目のif
ステートメントが正常に実行され、その4
は実際にl
を使用してリストappend
に追加されます。
さて..最初のif
statementが2番目のif
ステートメントで評価されているものの値を変更するとどうなりますか?
そして、はい、それは別の状況です。たとえば、変数x
があり、if
ステートメントを使用して、実際にx
値を変更したコードのブロックを評価したとします。ここで、同じ変数を評価する別のif
ステートメントを使用する場合、x
の値を最初の値と同じと見なしているため、x
は間違っています。実際、最初のif
が実行された後に変更されました。したがって、コードは正しくありません。
これはかなり頻繁に発生し、場合によっては明示的に変更することもできます。それがあなたのコードが振る舞うことを望むなら、そうです、あなたはうまくいく複数のif
を使うべきです。それ以外の場合は、Elif
を使用します。
私の例では、1番目のif
ブロックが実行され、x
の値が変更されます。これにより、2番目のif
は別のx
を評価します(その値は変更されました)。
このような場合にElif
が役立つのは、このようなことが起こらないようにするためです。これが、この機能を使用する主な利点です。他のsecondary複数のElif
ではなくif
を使用することの良い利点は、混乱を防ぎ、コードを読みやすくすることです。