web-dev-qa-db-ja.com

ifステートメントの条件評価順序に依存しても安全ですか?

my_varをNoneにできる場合、次の形式を使用することは悪い習慣ですか?

if my_var and 'something' in my_var:
    #do something

問題は、my_varがNoneの場合、'something' in my_varがTypeErrorをスローすることです。

または私が使うべきですか:

if my_var:
    if 'something' in my_var:
        #do something

または

try:
    if 'something' in my_var:
        #do something
except TypeError:
    pass

質問を言い換えると、上記のうちPython(存在する場合))のベストプラクティスはどれですか。

代替案は大歓迎です!

65
tgray

条件式の順序に依存することは安全です( Pythonリファレンスはこちら )、特に指摘する問題のため-一連の問題を引き起こす可能性がある評価を短絡できることは非常に便利です条件付き。

この種のコードは、ほとんどの言語で表示されます。

IF exists(variable) AND variable.doSomething()
    THEN ...
83
Daniel Lew

はい、安全です。言語リファレンスで明示的かつ非常に明確に定義されています。

表現 x and y最初にxを評価します。 xfalseの場合、その値が返されます。それ以外の場合は、yが評価され、結果の値が返されます。

表現 x or y最初にxを評価します。 xがtrueの場合、その値が返されます。それ以外の場合は、yが評価され、結果の値が返されます。

31
vartec

ここでは少し知識を深めているかもしれませんが、最良の答えは

if my_var is not None and 'something' in my_var:
    #do something

違いは、my_varからNoneまたはTrueへの暗黙的な変換ではなく、Falseの明示的なチェックです。

私はあなたのケースでは区別が重要ではないと確信していますが、より一般的なケースでは、変数がNoneではなくてもFalseに評価される可能性があります。たとえば、 0の整数値または空のリスト。

安全であるという他のほとんどのポスターの主張に反して、あなたが明示している限り、それは安全であると私は言います。確信がない場合は、この非常に不自然なクラスを検討してください。

class Contrived(object):
    def __contains__(self, s):
        return True
    def __nonzero__(self):
        return False

my_var = Contrived()
if 'something' in my_var:
    print "Yes the condition is true"
if my_var and 'something' in my_var:
    print "But this statement won't get reached."
if my_var is not None and 'something' in my_var:
    print "Whereas this one will."

はい、私はそれが現実的な例ではないことを知っていますが、特にNoneがデフォルトの関数引数を示すために使用される場合、実際のコードで変動が発生します。

2
Scott Griffiths

それは完全に安全で、私はいつもそれをします。

1
FogleBird

私はtry/exceptを使用しますが、それは変数について知っていることに依存します。

ほとんどの場合、変数が存在すると予想される場合は、try/exceptの方が操作は少なくなります。ほとんどの場合、変数がNoneであると予想している場合、IFステートメントの方が操作は少なくなります。

1
Jason Coon

それはそれほど単純ではありません。 C#の男として、私は次のようなことに慣れています。

if(x != null && ! string.isnullorempty(x.Name))
{
   //do something
}

上記は適切に機能し、期待どおりに評価されます。ただし、VB.Netでは、次の結果が予期しない結果になります。

If Not x Is Nothing **And** Not String.IsNullOrEmpty(x.Name) Then

   'do something

End If

上記は例外を生成します。正しい構文は

If Not x Is Nothing **AndAlso** Not String.IsNullOrEmpty(x.Name) Then

   'do something

End If

非常に微妙な違いに注意してください。これは私を約10分間混乱させました(時間が長すぎる)ため、他の言語でコーディングする場合、C#(およびその他)の人は非常に注意する必要があります。

1
Hans