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
を繰り返す必要はありません)?
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
を特に使用せずにデフォルト値をトリガーできます(たとえば、エラーオブジェクト)。
一部の言語では、この動作は エルビス演算子 と呼ばれます。
厳密に、
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")
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
「または」の動作に関するジュリアーノの答えに加えて、「速い」
>>> 1 or 5/0
1
だから、時にはそれは次のようなものの便利なショートカットかもしれません
object = getCachedVersion() or getFromDB()
これには答えがありますが、オブジェクトを扱う場合には別のオプションがあります。
次のようなオブジェクトがある場合:
{
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
のようになります。
@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)