web-dev-qa-db-ja.com

pythonでnullオブジェクト?

Pythonでnullオブジェクトをどうやって参照するのですか?

974
Lizard

Pythonでは、 'null'オブジェクトはシングルトンNoneです。

「なし」をチェックする最も良い方法は、恒等演算子isを使うことです。

if foo is None:
    ...
1331
Ben James

None、Pythonのnull?

Pythonにはnullはありませんが、代わりにNoneがあります。すでに述べたように、何かに値としてNoneが与えられていることをテストする最も正確な方法は、2つの変数が同じオブジェクトを参照していることをテストするis identity演算子を使うことです。

>>> foo is None
True
>>> foo = 'bar' 
>>> foo is None
False

基礎

Noneは1つしか存在できません

NoneはクラスNoneTypeの唯一のインスタンスであり、そのクラスをインスタンス化しようとするさらなる試みは同じオブジェクトを返します。これはNoneをシングルトンにします。 Pythonを初めて使う人は、NoneTypeに言及するエラーメッセージをよく見て、それが何であるか疑問に思います。私たちの個人的な見解では、これらのメッセージは単に名前でNoneに言及することができますが、すぐにわかるように、Noneはあいまいさの余地がほとんどないためです。 TypeErrorがこれを実行できない、または実行できないことを示すNoneTypeメッセージが表示された場合は、それができない方法で使用されているのは単にNoneであることを確認してください。

また、Noneは組み込み定数です。Pythonを起動するとすぐに、モジュール、クラス、関数のどこからでも使用できるようになります。対照的にNoneTypeはそうではありません、あなたはそのクラスのためにNoneを問い合わせることによってそれへの参照を最初に得る必要があるでしょう。

>>> NoneType
NameError: name 'NoneType' is not defined
>>> type(None)
NoneType

Noneの一意性はPythonの恒等関数id()で確認できます。オブジェクトに割り当てられた一意の番号を返します。各オブジェクトには1つあります。 2つの変数のIDが同じ場合、それらは実際には同じオブジェクトを指します。

>>> NoneType = type(None)
>>> id(None)
10748000
>>> my_none = NoneType()
>>> id(my_none)
10748000
>>> another_none = NoneType()
>>> id(another_none)
10748000
>>> def function_that_does_nothing(): pass
>>> return_value = function_that_does_nothing()
>>> id(return_value)
10748000

Noneは上書きできません

非常に古いバージョンのPython(2.4以前)では、Noneを再割り当てすることは可能でしたが、もうそうすることはできません。クラス属性としてでも、関数の範囲内でも。

# In Python 2.7
>>> class SomeClass(object):
...     def my_fnc(self):
...             self.None = 'foo'
SyntaxError: cannot assign to None
>>> def my_fnc():
        None = 'foo'
SyntaxError: cannot assign to None

# In Python 3.5
>>> class SomeClass:
...     def my_fnc(self):
...             self.None = 'foo'
SyntaxError: invalid syntax
>>> def my_fnc():
        None = 'foo'
SyntaxError: cannot assign to keyword

したがって、すべてのNone参照は同じであると仮定しても安全です。 "カスタム" Noneはありません。

Noneをテストするには、is演算子を使用します。

コードを書くとき、 なし のようにテストしたくなるかもしれません。

if value==None:
    pass

またはこのような虚偽をテストする

if not value:
    pass

あなたはその意味を理解する必要があります、そしてなぜそれがしばしば明白であることが良い考えであるか。

ケース1:値がNoneかどうかをテストする

なぜこれをするのか

value is None

のではなく

value==None

最初のものは以下と同等です。

id(value)==id(None)

value==Noneは実際にはこのように適用されますが

value.__eq__(None)

値が本当にNoneであれば、あなたはあなたが期待したものを得るでしょう。

>>> nothing = function_that_does_nothing()
>>> nothing.__eq__(None)
True

ほとんどの場合、結果は同じになりますが、__eq__()メソッドはクラス内でオーバーライドされて特別な動作を提供する可能性があるため、正確さの保証を無効にする扉を開きます。

このクラスを考えてください。

>>> class Empty(object):
...     def __eq__(self, other):
...         return not other

それであなたはそれをNoneで試してみてそれは機能します

>>> empty = Empty()
>>> empty==None
True

しかし、それからそれはまた空の文字列にも働きます

>>> empty==''
True

そしてまだ

>>> ''==None
False
>>> empty is None
False

ケース2:Noneをブール値として使用

次の2つのテスト

if value:
    # do something

if not value:
    # do something

実際には

if bool(value):
    # do something

if not bool(value):
    # do something

Noneは "falsey"です。つまり、ブール値にキャストするとFalseが返され、not演算子を適用するとTrueが返されます。ただし、Noneに固有のプロパティではありません。 False自体に加えて、このプロパティは空のリスト、タプル、セット、辞書、文字列、0、およびFalseを返す__bool__()マジックメソッドを実装するクラスのすべてのオブジェクトによって共有されます。

>>> bool(None)
False
>>> not None
True

>>> bool([])
False
>>> not []
True

>>> class MyFalsey(object):
...     def __bool__(self):
...         return False
>>> f = MyFalsey()
>>> bool(f)
False
>>> not f
True

したがって、次の方法で変数をテストするときは、テストに含めたり、テストから除外したりしているものに特に注意してください。

def some_function(value=None):
    if not value:
        value = init_value()

上記では、値が特にNoneに設定されているときにinit_value()を呼び出すことを意味しましたか、それとも0、空の文字列、または空のリストに設定された値も初期化を引き起こすべきです。私が言ったように、注意してください。 Pythonではよくあることですが、 明示的は暗黙的よりも優れています

実際にはNone

シグナル値として使用されるNone

NoneはPythonでは特別な地位を占めています。多くのアルゴリズムが例外的な値として扱うので、これはお気に入りのベースライン値です。このようなシナリオでは、条件が何らかの特別な処理(デフォルト値の設定など)を必要とすることを知らせるためのフラグとして使用できます。

Noneを関数のキーワード引数に割り当てて、それを明示的にテストすることができます。

def my_function(value, param=None):
    if param is None:
        # do something outrageous!

オブジェクトの属性にたどり着き、それから何か特別なことをする前に明示的にそれをテストしようとするときは、デフォルトとしてそれを返すことができます。

value = getattr(some_obj, 'some_attribute', None)
if value is None:
    # do something spectacular!

デフォルトでは、辞書のget()メソッドは存在しないキーにアクセスしようとするとNoneを返します。

>>> some_dict = {}
>>> value = some_dict.get('foo')
>>> value is None
True

添え字表記を使ってアクセスしようとした場合、KeyErrorが発生します。

>>> value = some_dict['foo']
KeyError: 'foo'

存在しないアイテムをポップしようとした場合も同様

>>> value = some_dict.pop('foo')
KeyError: 'foo'

通常はNoneに設定されているデフォルト値で抑制できます。

value = some_dict.pop('foo', None)
if value is None:
    # booom!

フラグと有効値の両方として使用されるNone

上で説明したNoneの使用は、それが有効な値と見なされていないときに適用されますが、何か特別なことをするためのシグナルのようなものです。ただし、Noneがどこから来たのかを知ることが重要な場合があります。なぜなら、それがシグナルとして使用されていても、それがデータの一部である可能性もあるからです。

getattr(some_obj, 'attribute_name', None)を使用してオブジェクトの属性を照会したときに、Noneは、アクセスしようとしていた属性がNoneに設定されているかどうか、またはオブジェクトにまったく含まれていないかどうかを通知しません。 some_dict.get('some_key')のような辞書からキーにアクセスするときと同じ状況で、some_dict['some_key']が見つからないのか、それがNoneに設定されているのかはわかりません。その情報が必要な場合、これを処理する通常の方法は、try/except構造内から属性またはキーに直接アクセスすることです。

try:
    # equivalent to getattr() without specifying a default
    # value = getattr(some_obj, 'some_attribute')
    value = some_obj.some_attribute
    # now you handle `None` the data here
    if value is None:
        # do something here because the attribute was set to None
except AttributeError:
    # we're now hanling the exceptional situation from here.
    # We could assign None as a default value if required.
    value = None 
    # In addition, since we now know that some_obj doesn't have the
    # attribute 'some_attribute' we could do something about that.
    log_something(some_obj)

Dictと同じです。

try:
    value = some_dict['some_key']
    if value is None:
        # do something here because 'some_key' is set to None
except KeyError:
    # set a default 
    value = None
    # and do something because 'some_key' was missing
    # from the dict.
    log_something(some_dict)

上記の2つの例は、オブジェクトと辞書のケースを処理する方法を示しています。同じことですが、そのためにはダブルアスタリスクキーワード引数を使用します。

def my_function(**kwargs):
    try:
        value = kwargs['some_key'] 
        if value is None:
            # do something because 'some_key' is explicitly 
            # set to None
    except KeyError:
        # we assign the default
        value = None
        # and since it's not coming from the caller.
        log_something('did not receive "some_key"')

Noneは有効な値としてのみ使用されます

あなたのコードが単にNoneフラグとNoneデータを区別するために上記のtry/exceptパターンで散らばっているのを見つけたならば、ただ別のテスト値を使ってください。一連の有効な値の範囲外の値がデータ構造のデータの一部として挿入され、特別な条件(境界、状態など)の制御とテストに使用されるパターンがあります。このような値は センチネル と呼ばれ、Noneがシグナルとして使用される方法で使用できます。 Pythonでセンチネルを作るのは簡単です。

undefined = object()

上記のundefinedオブジェクトはユニークで、プログラムにとって重要なことはほとんどしません。したがって、フラグとしてのNoneの代わりになる優れたものです。いくつかの注意点が適用されますが、それについてはコードの後に​​詳しく説明します。

機能付き

def my_function(value, param1=undefined, param2=undefined):
    if param1 is undefined:
        # we know nothing was passed to it, not even None
        log_something('param1 was missing')
        param1 = None


    if param2 is undefined:
        # we got nothing here either
        log_something('param2 was missing')
        param2 = None

口述とは

value = some_dict.get('some_key', undefined)
if value is None:
    log_something("'some_key' was set to None")

if value is undefined:
    # we know that the dict didn't have 'some_key'
    log_something("'some_key' was not set at all")
    value = None

オブジェクトあり

value = getattr(obj, 'some_attribute', undefined) 
if value is None:
    log_something("'obj.some_attribute' was set to None")
if value is undefined:
    # we know that there's no obj.some_attribute
    log_something("no 'some_attribute' set on obj")
    value = None

前述したように、カスタムセンチネルには注意点がいくつかあります。まず、それらはNoneのようなキーワードではないので、pythonはそれらを保護しません。上記のundefinedは、それが定義されているモジュール内の任意の場所でいつでも上書きできます。そのため、それらを公開して使用する方法には注意してください。次に、object()によって返されるインスタンスはシングルトンではありません、あなたがその呼び出しを10回行うと、あなたは10個の異なるオブジェクトを取得します。最後に、センチネルの使用法は非常に独特です。センチネルはそれが使用されているライブラリに固有のものであり、その範囲は一般にライブラリの内部に限定されるべきです。 「漏れる」べきではありません。外部コードは、その目的がライブラリのAPIを拡張または補足することである場合にのみ、認識されるようにしてください。

70
Michael Ekoka

他の言語のようにnullと呼ばれるのではなく、 None となります。このオブジェクトのインスタンスは常に1つだけなので、必要に応じて、x is Noneの代わりにx == None(識別情報の比較)で等価性をチェックできます。

61
AndiDog

Pythonでは、値が存在しないことを表すために、オブジェクトにはNone value(types.NoneType.None)、""(または_)を使用できます。文字列の場合はlen()== 0)。したがって:

if yourObject is None:  # if yourObject == None:
    ...

if yourString == "":  # if yourString.len() == 0:
    ...

"=="と "is"の違いについては、 "=="を使用してオブジェクトの同一性をテストするだけで十分です。ただし、「is」という操作はオブジェクト識別操作として定義されているため、「==」ではなく、それを使用する方がおそらく適切です。速度差さえあるかどうかわからない。

とにかく、あなたは見てみることができます:

27
Paolo Rovelli

Per 真理値テスト 、 'None'は直接FALSEとしてテストするので、最も単純な式で十分です。

if not foo:
0
artejera