AとAがNoneでない場合:


154

使ってもいいですか:

if A:

の代わりに

if A is not None:

後者はとても冗長に見えます。違いはありますか?

回答:


149

ステートメント

if A:

呼び出しA.__nonzero__()特別なメソッド名のドキュメントを参照)、その関数の戻り値を使用します。要約は次のとおりです。

object.__nonzero__(self)

真理値テストと組み込み操作を実装するために呼び出されbool()ます。返すべきであるFalseTrue、またはその整数同等01。このメソッドが定義されていない__len__()場合、が定義されていれば呼び出され、その結果がゼロ以外であればオブジェクトは真と見なされます。クラスがもも定義してい__len__()ない場合、__nonzero__()そのすべてのインスタンスはtrueと見なされます。

一方、

if A is not None:

参照のみを比較ANoneて、同じかどうかを確認します。


4
A is not None行う必要のある作業がはるかに少ないので、高速になります
John La Rooy '19年

40
@gnibbler私のテストによらない。if object(): passループあたりif object() is not None: pass〜0.130 usecですが、〜0.135 usecです。いずれにせよ、これら2つを選択するためにパフォーマンスを使用するのではなく、同等ではないため、動作の違いを確認してください。
Lauritz V. Thaulow、2011年

1
@gnibbler if A is not Noneは、比較のために組み込みのシングルトンNoneを比較するための中間ステップとしてロードする必要があるため、遅くなるようですA(を参照してくださいdis.dis())。私が間違っているがif A:Noneアイデンティティではなく真の値を実際にテストしたい場合は、より効率的であると思われる場合に修正してください。
cedbeu 2013年

2
@ cedbeu、Aの値に依存しているようです。私がテストしたところ、現在python -m timeit -s"a=0" "if a: pass" "else: pass"より高速ですpython -m timeit -s"a=0" "if a is None: pass" "else: pass"python -m timeit -s"a=1" "if a: pass" "else: pass"低速です。プラットフォームに依存する可能性があります。同じ結果が得られるかどうかを確認してください
John La Rooy 2013年

2
@ cedbeu、Python3では、すべてがはるかに高速ですが、is Noneテストは確かに私にとって最も低速でした。pypyでは、それらはすべてまったく同じように測定されました:)
John La Rooy 2013年

51

に書かれているように PEP8でように

  • のようなシングルトンとの比較 None は、常に 'is'または 'is not'を使用して行う必要があります等価演算子は使用しないでください。

    また、「もしxがNoneでない」ことを本当に意味している場合、 たとえば、デフォルトでNoneになっている変数または引数が他の値に設定されているかどうかをテストする場合は、「if x」を書くこと注意してください。他の値には、ブール値のコンテキストではfalseになる可能性のあるタイプ(コンテナーなど)がある場合があります。


7
うーん、これはあまり明確ではありませんが、OPには応答しません。PEPへの自動リダイレクトは、常に良い答えとは限りません。多くの場合、シングルトンを使用したIDテストではなくNone、真理値のチェックに関心があります。この場合、if A:より効率的に見えます(aをdis.dis()実行すると、組み込みをロードしてNoneと比較する追加の手順がありますが、他の場合if A is not None:にはaしかありませんjump_if)。
cedbeu 2013年

29
if x: #x is treated True except for all empty data types [],{},(),'',0 False, and None

だからと同じではありません

if x is not None # which works only on None

17

適切な結果がない場合、多くの関数はNoneを返します。たとえば.first()、結果に行がなかった場合、SQLAlchemyクエリのメソッドはNoneを返します。0を返す可能性のある値を選択していて、その値が実際に0かどうか、またはクエリにまったく結果がないかどうかを知る必要があるとします。

一般的なイディオムは、関数またはメソッドのオプションの引数にデフォルト値のNoneを指定し、その値がNoneであることをテストして、指定されているかどうかを確認することです。例えば:

def spam(eggs=None):
    if eggs is None:
        eggs = retrievefromconfigfile()

それと比較してください:

def spam(eggs=None):
    if not eggs:
        eggs = retrievefromconfigfile()

後者の場合、spam(0)またはを呼び出すとどうなりますかspam([])?関数は(誤って)値を渡していないことを検出しますeggs、デフォルト値を計算します。それはおそらくあなたが望むものではありません。

または、「特定のアカウントのトランザクションのリストを返す」のような方法を想像してみてください。アカウントが存在しない場合、Noneが返される可能性があります。これは、空のリストを返すこととは異なります(つまり、「このアカウントは存在しますが、トランザクションは記録されていません)。

最後に、データベースに戻ります。NULLと空の文字列の間には大きな違いがあります。空の文字列は通常、「ここに値があり、その値はまったく何もない」と言います。NULLは、「この値は入力されていません」と言います。

これらのいずれの場合も、を使用する必要がありますif A is None。特定の値をチェックしている-なし-「たまたまFalseにキャストされる値」だけではない。


10

彼らは非常に異なることをします。

以下のチェックAが値以外のものを持っている場合はFalse[]None''0。A のをチェックします

if A:

以下は、AがNoneと異なるオブジェクトかどうかをチェックします。AとNone の参照(メモリアドレス)をチェックして比較します

if A is not None:

更新:詳細説明

多くの場合、2つは同じことをするように見えるので、多くの人がそれらを交換可能に使用します。これは本当に悪い考えです。2つが同じ結果をもたらす理由は、インターニングのようなインタープリター/コンパイラーの最適化による純粋な偶然によるものです。や他の何かのものです。

これらの最適化を念頭に置いて、同じ値の整数と文字列は、同じメモリ空間を使用することになります。これはおそらく、2つの別々の文字列が同じであるかのように動作する理由を説明しています。

> a = 'test'
> b = 'test'
> a is b
True
> a == b
True

他のことは同じように動作しません。

> a = []
> b = []
> a is b
False
> a == b
True

2つのリストには明らかに独自の記憶があります。驚くべきことに、タプルは文字列のように動作します。

> a = ()
> b = ()
> a is b
True
> a == b
True

これはタプルが変更されないことが保証されているためと考えられ、同じメモリを再利用することには意味があります。

これの結論は偶然に頼ることができないということです。アヒルのように鳴くからといって、それがアヒルであるとは限りません。使用isして==、あなたが本当にチェックしたいものに応じて。これらのことはis、私たちがよくそれを読み飛ばす散文のように読まれるので、デバッグが難しい場合があります。


Noneシングルトンであり、これは実装の詳細ではありません(intやstring interningとは異なります)。私があなたの言っていることを理解しているとは思いません。
Lev Levitsky 2017

@LevLevitsky私のポイントは、インターンとNoneは異なる、intまたはstrインターンが原因の動作ではありません。私のポイントはそれでisあり==、さまざまなことをチェックしています。最初はメモリアドレスをチェックし、2番目はメモリアドレスの内容をチェックします。
ピティコス2017

@LevLevitsky回答を少しわかりやすくするために編集しました。
ピティコス2017

7

if A: Aが0、False、空の文字列、空のリスト、またはNoneの場合は、falseを示します。これにより、望ましくない結果が生じる可能性があります。


1
また、空のリスト、空のセット、空のタプルなど、他の多くの値も含まれます。本質的に、docs.python.org/3/ library / stdtypes.html#truth-value- testingごとに真実ではないもの。
jarmod

6

私が見たほとんどのガイドはあなたが使うべきであることを示唆しています

もし:

より具体的な理由がない限り。

若干の違いがあります。空のリストや0など、Falseを返すNone以外の値があるので、実際に何をテストしているのかを考えてください。


5

どれもPythonでは特別な値であり、通常は初期化されていない変数を指定します。Aにこの特定の値がないかどうかをテストするには、次を使用します。

if A is not None

Falsey値はPythonのオブジェクトの特別なクラスです(例:false、[])。Aが誤っているかどうかをテストするには:

if not A

したがって、2つの式は同じではなく、それらを同義語として扱わない方がよいでしょう。


PS Noneも誤っているため、最初の式は2番目の式を意味します。しかし、2つ目は、None以外の誤った値をカバーしています。ここで... AのNone以外に他の偽の値を使用できないことが確実な場合は、最初の式を2番目の式に置き換えることができます。


それはあなたが間違っているということではありませんが、この答えはすでにこれをカバーしています。

よろしければ、反対票を削除していただきますようお願いいたします。私の回答は他のすべての回答と同等ですが、あなたが参照する回答ではそれほどではないかもしれませんが、別の視点から提示されており、誰かにとって理解しやすいかもしれません。さらに、私がSOへの反対票を見たとき、私は間違った答えを仮定します...あなたが認めているのはそうではありません。
mircealungu 2016

まあ、その仮定は不完全です。それは間違っているか、単に役に立たない可能性があります。私が述べたあなたの答えはすでにカバーされていたので、私はそれが有用であるとは確信していません。

4

状況によります。

ある種のコレクションになることをif A:期待しAているときに使用します。コレクションが空でない場合にのみブロックを実行します。これにより、呼び出し側は、空であるかどうかにかかわらず、適切に動作するコレクションを渡し、期待どおりの動作をさせることができます。また、ブロックの実行を許可NoneおよびFalse抑制します。これは、コードを呼び出すのに便利な場合があります。

OTOH、私は期待している場合A、いくつかの完全に任意のオブジェクトであることを、それはにデフォルト設定されている可能性がNone、私は、いつも使うif A is not None呼び出すコードが故意に空のコレクション、空の文字列、または0の値を持つ数値型への参照を渡すことができたとして、またはboolean False、またはブールコンテキストでたまたまfalseとなるクラスインスタンス。

そして、その一方で、Aより具体的なもの(たとえば、メソッドを呼び出すクラスのインスタンス)を期待している場合は、デフォルトでになっている可能性がありNone、デフォルトのブール変換はすべてのサブクラスに強制することを気にしないクラスのプロパティです。次にif A:、追加の12文字を入力する手間の負担を軽減するために使用します。


3

というファイルを作成test.pyし、インタプリタで実行しました。目的を変更して、舞台裏での状況をテストすることができます。

import dis

def func1():

    matchesIterator = None

    if matchesIterator:

        print( "On if." );

def func2():

    matchesIterator = None

    if matchesIterator is not None:

        print( "On if." );

print( "\nFunction 1" );
dis.dis(func1)

print( "\nFunction 2" );
dis.dis(func2)

これがアセンブラの違いです。

ソース:

>>> import importlib
>>> reload( test )

Function 1
  6           0 LOAD_CONST               0 (None)
              3 STORE_FAST               0 (matchesIterator)

  8           6 LOAD_FAST                0 (matchesIterator)
              9 POP_JUMP_IF_FALSE       20

 10          12 LOAD_CONST               1 ('On if.')
             15 PRINT_ITEM
             16 PRINT_NEWLINE
             17 JUMP_FORWARD             0 (to 20)
        >>   20 LOAD_CONST               0 (None)
             23 RETURN_VALUE

Function 2
 14           0 LOAD_CONST               0 (None)
              3 STORE_FAST               0 (matchesIterator)

 16           6 LOAD_FAST                0 (matchesIterator)
              9 LOAD_CONST               0 (None)
             12 COMPARE_OP               9 (is not)
             15 POP_JUMP_IF_FALSE       26

 18          18 LOAD_CONST               1 ('On if.')
             21 PRINT_ITEM
             22 PRINT_NEWLINE
             23 JUMP_FORWARD             0 (to 26)
        >>   26 LOAD_CONST               0 (None)
             29 RETURN_VALUE
<module 'test' from 'test.py'>

2

前者はよりPythonic(より良い表意コード)ですが、AがFalse(Noneではない)の場合はブロックを実行しません。


7
-1。@kleshが言及するように、PEP8はを使用するように言っていますis/is not None。次のPEP8はPythonicです。さらに、2つのテストは異なります。
JCotton、2012

1

python> = 2.6、

次のように書けば

if A:

警告を生成します、

FutureWarning:このメソッドの動作は将来のバージョンで変更されます。代わりに、特定の 'len(elem)'または 'elem is not None'テストを使用してください。

だから私たちは使うことができます

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