web-dev-qa-db-ja.com

C#のnull合体演算子に相当するPythonがありますか?

C#には、 null-coalescing operator??として記述)があり、割り当て中に簡単な(短い)nullチェックが可能です。

string s = null;
var other = s ?? "some default value";

同等のpythonがありますか?

私ができることを知っています:

s = None
other = s if s else "some default value"

しかし、もっと短い方法はありますか(sを繰り返す必要はありません)?

242
other = s or "some default value"

OK、or演算子がどのように機能するかを明確にする必要があります。これはブール演算子であるため、ブールコンテキストで機能します。値がブール値でない場合、演算子の目的のためにブール値に変換されます。

or演算子は、TrueまたはFalseのみを返すわけではないことに注意してください。代わりに、第1オペランドの評価がtrueの場合は第1オペランドを返し、第1オペランドの評価がfalseの場合は第2オペランドを返します。

この場合、式x or yは、xである場合にTrueを返すか、ブール値に変換されたときにtrueと評価されます。それ以外の場合は、yを返します。ほとんどの場合、これはC♯のヌル合体演算子とまったく同じ目的に役立ちますが、留意してください。

42    or "something"    # returns 42
0     or "something"    # returns "something"
None  or "something"    # returns "something"
False or "something"    # returns "something"
""    or "something"    # returns "something"

変数sを使用して、クラスのインスタンスへの参照またはNoneのいずれかを保持する場合(クラスがメンバー__nonzero__()および__len__()を定義しない限り)、使用するのは安全です。 null合体演算子と同じセマンティクス。

実際、このPythonの副作用があると便利な場合もあります。どの値がfalseと評価されるか知っているので、これを使用して、Noneを特に使用せずにデフォルト値をトリガーできます(たとえば、エラーオブジェクト)。

一部の言語では、この動作は エルビス演算子 と呼ばれます。

350
Juliano

厳密に、

other = s if s is not None else "default value"

そうでない場合、s = False"default value"になりますが、これは意図したものではない場合があります。

これを短くしたい場合は、次を試してください:

def notNone(s,d):
    if s is None:
        return d
    else:
        return s

other = notNone(s, "default value")
51
Hugh Bothwell

Noneではない最初の引数を返す関数は次のとおりです。

def coalesce(*arg):
  return reduce(lambda x, y: x if x is not None else y, arg)

# Prints "banana"
print coalesce(None, "banana", "phone", None)

reduce()は、最初の引数がNoneでない場合でも、すべての引数を不必要に反復する可能性があるため、このバージョンも使用できます。

def coalesce(*arg):
  for el in arg:
    if el is not None:
      return el
  return None
38
mortehu

「または」の動作に関するジュリアーノの答えに加えて、「速い」

>>> 1 or 5/0
1

だから、時にはそれは次のようなものの便利なショートカットかもしれません

object = getCachedVersion() or getFromDB()
3
Orca

これには答えがありますが、オブジェクトを扱う場合には別のオプションがあります。

次のようなオブジェクトがある場合:

{
   name: {
      first: "John",
      last: "Doe"
   }
}

次を使用できます。

obj.get(property_name, value_if_null)

好む:

obj.get("name", {}).get("first", "Name is missing") 

{}をデフォルト値として追加することにより、「名前」が欠落している場合、空のオブジェクトが返され、次のgetにパススルーされます。これは、C#のnull-safe-navigationに似ており、obj?.name?.firstのようになります。

3
Craig

@Hugh Bothwell、@ mortehu、@ glglglによる回答について。

テスト用のセットアップデータセット

import random

dataset = [random.randint(0,15) if random.random() > .6 else None for i in range(1000)]

実装を定義する

def not_none(x, y=None):
    if x is None:
        return y
    return x

def coalesce1(*arg):
  return reduce(lambda x, y: x if x is not None else y, arg)

def coalesce2(*args):
    return next((i for i in args if i is not None), None)

テスト機能を作成する

def test_func(dataset, func):
    default = 1
    for i in dataset:
        func(i, default)

python 2.7を使用したmac i7 @ 2.7Ghzでの結果

>>> %timeit test_func(dataset, not_none)
1000 loops, best of 3: 224 µs per loop

>>> %timeit test_func(dataset, coalesce1)
1000 loops, best of 3: 471 µs per loop

>>> %timeit test_func(dataset, coalesce2)
1000 loops, best of 3: 782 µs per loop

明らかにnot_none関数はOPの質問に正しく答え、「偽の」問題を処理します。また、最速で読みやすいです。多くの場所でロジックを適用する場合は、明らかに最適な方法です。

Iterableで最初のnull以外の値を見つけたいという問題がある場合は、@ mortehuの応答が最適です。しかし、それはの異なる問題の解決策ですが、その場合は部分的に処理できます。反復可能なANDデフォルト値を取ることはできません。最後の引数は返されるデフォルト値になりますが、その場合はイテレート可能変数を渡すことはなく、最後の引数がデフォルト値であることも明示的ではありません。

その後、以下を実行できますが、単一値のユースケースにはnot_nullを使用します。

def coalesce(*args, **kwargs):
    default = kwargs.get('default')
    return next((a for a in arg if a is not None), default)
0
debo