PythonでC#のnull結合演算子に相当するものはありますか?


301

C#には、割り当て中にnullを結合する演算子(として記述??)があり、割り当て時に(短い)nullチェックを簡単に行うことができます。

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

同等のPythonはありますか?

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

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

しかし、もっと短い方法はありsますか(繰り返す必要がない場合)?


14
??オペレータは次のように提案されているPEP 505
200_success

回答:


421
other = s or "some default value"

わかりました、それはorオペレータがどのように働くか明確にされなければなりません。これはブール演算子なので、ブールコンテキストで機能します。値がブール値でない場合、演算子の目的でブール値に変換されます。

or演算子はTrueor だけを返さないことに注意してくださいFalse。代わりに、最初のオペランドがtrueと評価された場合は最初のオペランドを返し、最初のオペランドがfalseと評価された場合は2番目のオペランドを返します。

この場合、式x or yはブール値に変換された場合、またはtrueと評価されたx場合に戻りますTrue。それ以外の場合はを返しますy。ほとんどの場合、これはC♯のnull結合演算子と同じ目的に役立ちますが、次の点に注意してください。

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具体的に(エラーオブジェクトなど)を使用せずにデフォルト値をトリガーできます。

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


3
これは同じように機能しますか?つまりs、有効な値であるが真実ではない場合、それは壊れますか?(私はPythonを知らないので、「トルシー」の概念が適用されるかどうかわかりません。)
cHao

9
定数0に加えてNone、0 、、および空のコンテナ(文字列を含む)はfalseと見なされますFalse。他のほとんどすべてが本当であると考えられます。ここでの主な危険は、文字列ではなく真の値を取得することですが、一部のプログラムでは問題になりません。
キンダル

25
この使用他は、 sがNoneの場合は、デフォルト値を取得しますかFalseたかっれるものではないかもしれません。
pafcu

6
これによって引き起こされる不明瞭なバグもたくさんあります。たとえば、Python 3.5より前のdatetime.time(0)バージョンも、不正解でした。
Antti Haapala 2016年

19
これは悪いです。その落とし穴についての通知を追加することをお勧めします。そしてそれを使用しないことをお勧めします。
Mateen Ulhaq 2018

61

厳密には、

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")

1
Consider x()?.y()?.z()
ヌレティン

40

これは、最初の引数ではない関数を返す関数です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

23
def coalesce(*arg): return next((a for a in arg if a is not None), None)1行で最後の例と同じことを行います。
glglgl 2014年

2
私は人々が他のsytnaxなどかどうか説明したいと思うが、合体は任意の引数リストを取るので、これが本当にトップの答えになるはずです。
Eric Twilegar、2014

2
glglglが最良の答えです。大規模なテスト配列でtimeitを使用しましたが、reduceの実装は許容できないほど遅く、for / ifバージョンの複数行が最も速く、次の実装はわずかに遅れています。シンプルさと簡潔さを考慮すると、次のバージョンは全体として最高です。
粘土

3
@glglglには興味深いスニペットがあります。残念ながらPythonには名前渡しがないため、このような合体はショートサーキットではありません。すべての引数は、コードが実行される前に評価されます。
user1338062 2018

Consider x()?.y()?.z()
ヌレチン

5

私はこれが答えられていることを理解していますが、オブジェクトを処理するときに別のオプションがあります。

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

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

以下を使用できます。

obj.get(property_name, value_if_null)

お気に入り:

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

{}デフォルト値として追加することにより、「name」が欠落している場合、空のオブジェクトが返され、次のgetに渡されます。これは、C#のnullセーフナビゲーションに似ていますobj?.name?.first


すべてのオブジェクトにがあるわけではありません.get。これは、dictのようなオブジェクトに対してのみ機能します
ティムディール

getattr()もカバーするために回答編集を提出しています。
dgw

geton dictは、値がNoneの場合はデフォルトのパラメーターを使用しませんが、キーがdictにないために値が存在しない場合はデフォルトのパラメーターを使用します。結果として{'a': None}.get('a', 'I do not want None')あなたにまだ与えるでしょうNone
Patrick Mevzek

3

「または」の振る舞いに関するジュリアーノの回答に加えて、それは「速い」

>>> 1 or 5/0
1

時々それはのようなもののための便利なショートカットかもしれません

object = getCachedVersion() or getFromDB()

17
あなたが探している用語は「短絡」です。
jpmc26 2014年

1

さらに、単一の値に対する@Bothwellsの回答(私が好む)に加えて、関数の戻り値の割り当てをnullチェックするために、新しいwalrus-operatorを使用できます(python3.8以降)。

def test():
    return

a = 2 if (x:= test()) is None else x

したがって、test(のようにa = 2 if test() is None else test())関数を2回評価する必要はありません。


1

次のような複数のヌル合体操作をネストする必要がある場合:

model?.data()?.first()

これはで簡単に解決できる問題ではありませんor。また、で解決することはできません.get()辞書タイプまたは類似が必要です(と、とにかく入れ子にすることはできません)またはそのgetattr()NoneTypeが属性を持っていないときに例外をスローしますました。

言語にnullの合体を追加することを検討している関連するPIPはPEP 505であり、ドキュメントに関連する議論はpython-ideasスレッドにあります。


0

@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の質問に正しく回答し、「誤りのある」問題を処理します。また、これは最も速く、最も読みやすいものです。ロジックを多くの場所に適用する場合、それが明らかに最良の方法です。

イテラブルで最初のnull以外の値を検索する必要がある場合は、@ mortehuの応答で解決できます。しかし、それはOP とは異なる問題の解決策ですが、そのケースを部分的に処理できます。反復可能かつデフォルト値を取ることはできません。最後の引数は返されるデフォルト値になりますが、その場合は反復可能オブジェクトを渡さないため、最後の引数がデフォルトの値であることは明示されていません。

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

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

0

この問題の実行可能な解決策を探してここでつまずいた私のような人にとって、変数が未定義である可能性がある場合、私が得た最も近いものは次のとおりです:

if 'variablename' in globals() and ((variablename or False) == True):
  print('variable exists and it\'s true')
else:
  print('variable doesn\'t exist, or it\'s false')

グローバルをチェックインするときは文字列が必要ですが、その後、値をチェックするときに実際の変数が使用されることに注意してください。

変数の存在の詳細: 変数が存在するかどうかを確認するにはどうすればよいですか?


1
(variablename or False) == Trueと同じvariablename == True
マイク

-2
Python has a get function that its very useful to return a value of an existent key, if the key exist;
if not it will return a default value.

def main():
    names = ['Jack','Maria','Betsy','James','Jack']
    names_repeated = dict()
    default_value = 0

    for find_name in names:
        names_repeated[find_name] = names_repeated.get(find_name, default_value) + 1

辞書内で名前が見つからない場合は、default_valueを返します。名前が存在する場合は、既存の値に1を追加します。

これが役に立てば幸い


1
こんにちは、Stack Overflowへようこそ。既存の回答ではまだカバーされていなかった回答の新しい情報は何ですか?たとえば、@ Craigの回答を参照してください
Gricey

-6

以下の2つの関数は、多くの変数テストケースを処理するときに非常に役立つことがわかりました。

def nz(value, none_value, strict=True):
    ''' This function is named after an old VBA function. It returns a default
        value if the passed in value is None. If strict is False it will
        treat an empty string as None as well.

        example:
        x = None
        nz(x,"hello")
        --> "hello"
        nz(x,"")
        --> ""
        y = ""   
        nz(y,"hello")
        --> ""
        nz(y,"hello", False)
        --> "hello" '''

    if value is None and strict:
        return_val = none_value
    elif strict and value is not None:
        return_val = value
    elif not strict and not is_not_null(value):
        return_val = none_value
    else:
        return_val = value
    return return_val 

def is_not_null(value):
    ''' test for None and empty string '''
    return value is not None and len(str(value)) > 0

5
この種のものは、他の言語からインポートされたわずかに異なる用語の集まり(たとえば、「null」と「nz」はどちらもPythonのコンテキストでは何も意味しない)に加えて、バリアント(厳密または非厳密!)を追加します。これは混乱を増すだけです。明示的な「is None」チェックは、使用する必要があるものです。さらに、関数呼び出しを使用するときにオペレーターが実行できるショートカットのセマンティクスの利点はありません。
spookylukey 2017
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.