Pythonで「if someobj == None:」よりも「if notobj:」の方が優れているのはなぜですか?


127

私はこのようなコードのいくつかの例を見てきました:

if not someobj:
    #do something

しかし、私はなぜしないのか疑問に思っています:

if someobj == None:
    #do something

違いはありますか?一方が他方よりも有利ですか?


13
通常、「someobj is None」は「someobj == None」よりも好ましい
Aaron Maenpaa

XがNoneでない場合の疑似コードはどうですか?またはX != None
チャーリーパーカー、

この質問は他の質問よりも詳細です...称賛...
alamin

回答:


187

最初のテストでは、Pythonはまだbool値になっていない場合、オブジェクトを値に変換しようとします。大まかに、私たちは目的を尋ねています:あなたは意味がありますか?これは、次のアルゴリズムを使用して行われます。

  1. オブジェクトに__nonzero__特別なメソッドがある場合(数値組み込み関数やintfloat同様)、このメソッドを呼び出します。bool直接使用されるint値、またはFalseゼロと等しいと見なされる値を返す必要があります。

  2. オブジェクトがある場合はそれ以外の場合は、__len__(DOコンテナ組み込み関数など、特殊な方法でlistdictsettuple、...)を、それがコンテナを考えると、このメソッドを呼び出しFalse、それは(長さがゼロである)空の場合。

  3. それ以外の場合は、オブジェクトは考慮されますが、そうでTrueないNone場合は考慮されFalseます。

2番目のテストでは、オブジェクトがと等しいかどうか比較されNoneます。ここでは、オブジェクトに「この他の値と等しいですか?」と尋ねています。これは、次のアルゴリズムを使用して行われます。

  1. オブジェクトに__eq__メソッドがある場合、それが呼び出され、戻り値が値に変換されて、boolの結果を決定するために使用されifます。

  2. それ以外の場合、オブジェクトに__cmp__メソッドがある場合、それが呼び出されます。この関数intは、2つのオブジェクトの順序を示すを返す必要があります(-1if self < other0if self == other+1if self > other)。

  3. それ以外の場合、オブジェクトの同一性が比較されます(つまり、isオペレーターがテストできるように、それらは同じオブジェクトへの参照です)。

is演算子を使用して別のテストが可能です。オブジェクトに「この特定のオブジェクトですか」と尋ねます。

一般に、最初のテストを数値以外の値で使用し、同じ性質のオブジェクト(2つの文字列、2つの数値など)を比較する場合の同等性のテストを使用し、次の場合にのみIDを確認することをお勧めします。センチネル値を使用する(例:Noneのメンバーフィールドに対して初期化されていないこと、getattrまたはまたは__getitem__メソッドを使用する場合)

要約すると、次のようになります。

>>> class A(object):
...    def __repr__(self):
...        return 'A()'
...    def __nonzero__(self):
...        return False

>>> class B(object):
...    def __repr__(self):
...        return 'B()'
...    def __len__(self):
...        return 0

>>> class C(object):
...    def __repr__(self):
...        return 'C()'
...    def __cmp__(self, other):
...        return 0

>>> class D(object):
...    def __repr__(self):
...        return 'D()'
...    def __eq__(self, other):
...        return True

>>> for obj in ['', (), [], {}, 0, 0., A(), B(), C(), D(), None]:
...     print '%4s: bool(obj) -> %5s, obj == None -> %5s, obj is None -> %5s' % \
...         (repr(obj), bool(obj), obj == None, obj is None)
  '': bool(obj) -> False, obj == None -> False, obj is None -> False
  (): bool(obj) -> False, obj == None -> False, obj is None -> False
  []: bool(obj) -> False, obj == None -> False, obj is None -> False
  {}: bool(obj) -> False, obj == None -> False, obj is None -> False
   0: bool(obj) -> False, obj == None -> False, obj is None -> False
 0.0: bool(obj) -> False, obj == None -> False, obj is None -> False
 A(): bool(obj) -> False, obj == None -> False, obj is None -> False
 B(): bool(obj) -> False, obj == None -> False, obj is None -> False
 C(): bool(obj) ->  True, obj == None ->  True, obj is None -> False
 D(): bool(obj) ->  True, obj == None ->  True, obj is None -> False
None: bool(obj) -> False, obj == None ->  True, obj is None ->  True

4
技術的には正しいですが、これはタプル、リスト、dicts、strs、unicodes、ints、floatsなどがゼロ以外であることを説明していません。ゼロ以外のカスタムメソッドに依存するよりも、組み込み型の真理値に依存する方がはるかに一般的です。
ddaa 2008

50

これらは実際にはどちらも悪い習慣です。むかしむかし、NoneとFalseを同じように何気なく扱うことは問題ないと考えられていました。ただし、Python 2.2以降、これは最適なポリシーではありません。

あなたがやるときはまず、if xまたはif not xテストの種類を、Pythonは暗黙的に変換する必要がありxブールします。bool関数のルールは、Falseである多くのことを記述しています。それ以外はすべて真です。xの値がそもそも適切にブール値でなかった場合、この暗黙の変換は実際に言う最も明確な方法ではありません。

Python 2.2より前のバージョンでは、bool関数はなかったため、さらに不明確でした。

次に、実際にを使用してテストしないでください== None。とを使用する必要がis Noneありis not Noneます。

PEP 8、Style Guide for Python Codeを参照してください。

- Comparisons to singletons like None should always be done with
  'is' or 'is not', never the equality operators.

  Also, beware of writing "if x" when you really mean "if x is not None"
  -- e.g. when testing whether a variable or argument that defaults to
  None was set to some other value.  The other value might have a type
  (such as a container) that could be false in a boolean context!

シングルトンはいくつありますか?五:NoneTrueFalseNotImplementedEllipsisNotImplementedor を使用する可能性は非常に低くEllipsis、また言うこともないのでif x is True(単純if xである方がはるかに明確であるため)、テストするのはだけNoneです。


3
2番目の形式は、明らかに悪い習慣ではありません。PEP 8はif xを2回使用することを推奨しています。最初に(lenを使用する代わりに)シーケンスについて、次に(isを使用する代わりに)TrueおよびFalseについて。私が見たほとんどすべてのPythonコードは、xの場合とxでない場合に使用します。
Antti Rasinen 2008

35

なぜならNone、偽りと見なされるのはそれだけではないからです。

if not False:
    print "False is false."
if not 0:
    print "0 is false."
if not []:
    print "An empty list is false."
if not ():
    print "An empty tuple is false."
if not {}:
    print "An empty dict is false."
if not "":
    print "An empty string is false."

False0()[]{}および""すべて異なっているNoneあなたの2つのコードスニペットがあるので、ないと同等。

さらに、次の点を考慮してください。

>>> False == 0
True
>>> False == ()
False

if object:等価チェックではありません0()[]None{}、などです全て互いに異なるが、それらはすべて、評価 Falseに。

これは、次のような短絡式の背後にある「魔法」です。

foo = bar and spam or eggs

これは以下の略記です:

if bar:
    foo = spam
else:
    foo = eggs

あなたは本当に書くべきですが:

foo = spam if bar else egg

あなたの最後の質問に関しては、それらは同等です。
Sylvain Defresne 2008

また、 ""がFalseであるため、どちらも正しくありません。2番目は '( ""、)または( "s"、)'と読みます。とにかく、最新バージョンのpythonには適切な3項演算子があります。このエラーが発生しやすいハックは禁止する必要があります。
ddaa 2008


3

頼めば

if not spam:
    print "Sorry. No SPAM."

スパム__nonzero__メソッドが呼び出されます。Pythonマニュアルから:

__nonzero__self)真理値テストと組み込みオペレーションbool();を実装するために呼び出されます。このメソッドが定義されていない場合、定義されていれば__len __()が呼び出されます(以下を参照)。クラスが__len __()も__nonzero __()も定義しない場合、そのインスタンスはすべてtrueと見なされます。

頼めば

if spam == None:
    print "Sorry. No SPAM here either."

スパム__eq__メソッドは、引数Noneで呼び出されます。

カスタマイズの可能性の詳細については、https: //docs.python.org/reference/datamodel.html#basic-customizationにあるPythonのドキュメントをご覧ください。


2

これら2つの比較は、異なる目的に役立ちます。前者は何かのブール値をチェックし、2番目はNone値のIDをチェックします。


1
完全に正確にするために、2番目のチェックでは-equality-がNoneの値でチェックされます。 "someobj is None"はIDをチェックします。
マシュー・トレヴァー

0

1つ目は、最初の例の方が短く、見栄えが良くなっています。他の投稿と同様に、どちらを選択するかは、比較で本当に何をしたいかによって異なります。


0

答えは「場合によります」です。

このコンテキストでは、0、 ""、[]およびFalse(完全ではないリスト)がNoneと同等であると考える場合、最初の例を使用します。


0

個人的に、私は言語間で一貫したアプローチを選択しましたif (var)。varがbooleanとして宣言されている(またはCで特定の型がないなどのように定義されている)場合のみ、私は(または同等の)方法をとります。ここで誤って別の型を使用しないbように、これらの変数の前に(bVar実際にはそうなるように)を付けています。
ブール値への暗黙的なキャストはあまり好きではありません。複雑で複雑なルールが多数ある場合はなおさらです。

もちろん、人々は反対します。さらに進んif (bVar == true)でいる人もいますが、私の仕事のJavaコードで(私の趣味には冗長すぎます!)見えたり、あまりにもコンパクトな構文を愛しすぎたりwhile (line = getNextLine())(あいまいすぎたり)しています。

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