W języku C # występuje operator koalescencji zerowej (zapisany jako ??
), który umożliwia łatwe (krótkie) sprawdzanie wartości zerowej podczas przypisywania:
string s = null;
var other = s ?? "some default value";
Czy istnieje odpowiednik Pythona?
Wiem, że mogę:
s = None
other = s if s else "some default value"
Ale czy jest jeszcze krótsza droga (gdzie nie muszę powtarzać s
)?
python
null-coalescing-operator
Klaus Byskov Pedersen
źródło
źródło
??
Operator zaproponowano PEP 505 .Odpowiedzi:
Ok, należy wyjaśnić, jak
or
działa operator. Jest to operator logiczny, więc działa w kontekście logicznym. Jeśli wartości nie są logiczne, są one konwertowane na logiczne dla celów operatora.Pamiętaj, że
or
operator nie zwraca tylkoTrue
lubFalse
. Zamiast tego zwraca pierwszy operand, jeśli pierwszy operand ma wartość true, i zwraca drugi operand, jeśli pierwszy operand ma wartość false.W takim przypadku wyrażenie
x or y
zwraca wartość,x
jeśli jest,True
lub zwraca wartość true po przekonwertowaniu na wartość logiczną. W przeciwnym razie zwracay
. W większości przypadków będzie to służyć temu samemu celowi operatora zerowego koalescencji C♯, ale należy pamiętać:Jeśli użyjesz swojej zmiennej
s
do przechowywania czegoś, co jest albo odwołaniem do instancji klasy lubNone
(o ile twoja klasa nie definiuje członków__nonzero__()
i__len__()
), możesz bezpiecznie stosować tę samą semantykę, co operator zerowania.W rzeczywistości przydatne może być wywołanie tego efektu ubocznego Pythona. Ponieważ wiesz, które wartości mają wartość false, możesz użyć tego do wyzwolenia wartości domyślnej bez
None
specjalnego użycia (na przykład obiekt błędu).W niektórych językach takie zachowanie jest nazywane operatorem Elvisa .
źródło
s
to się zepsuje, jeśli jest prawidłową wartością, ale nie jest prawdą? (Nie znam Pythona, więc nie jestem pewien, czy ma zastosowanie koncepcja „prawdy”.)None
i puste kontenery (w tym ciągi) są uważane za fałsz, oprócz stałejFalse
. Większość wszystkiego jest uważana za prawdę. Powiedziałbym, że głównym niebezpieczeństwem byłoby uzyskanie prawdziwej, ale nie łańcuchowej wartości, ale nie będzie to problemem w niektórych programach.datetime.time(0)
był także falsy!Rygorystycznie,
W przeciwnym razie
s = False
stanie się"default value"
, co może nie być tym, co było zamierzone.Jeśli chcesz to skrócić, spróbuj:
źródło
Consider x()?.y()?.z()
Oto funkcja, która zwróci pierwszy argument, który nie jest
None
:reduce()
może niepotrzebnie powtarzać wszystkie argumenty, nawet jeśli pierwszy argument nie jestNone
, więc możesz również użyć tej wersji:źródło
def coalesce(*arg): return next((a for a in arg if a is not None), None)
robi to samo co twój ostatni przykład w jednej linii.Consider x()?.y()?.z()
Zdaję sobie sprawę, że na to odpowiedź, ale istnieje inna opcja, gdy masz do czynienia z przedmiotami.
Jeśli masz obiekt, który może być:
Możesz użyć:
Lubić:
Dodając
{}
jako wartość domyślną, jeśli brakuje „name”, pusty obiekt jest zwracany i przekazywany do następnego pobrania. Jest to podobne do nawigacji null-safe-w C #, co byłoby jakobj?.name?.first
.źródło
.get
, działa to tylko w przypadku obiektów podobnych dogetattr()
.get
on dict nie używa parametru domyślnego, jeśli wartością jest None, ale używa parametru domyślnego, jeśli wartość nie istnieje, ponieważ klucza nie ma w dict.{'a': None}.get('a', 'I do not want None')
nadal da ciNone
w rezultacie.Oprócz odpowiedzi Juliano na temat zachowania „lub”: jest „szybki”
Czasami może to być przydatny skrót do takich rzeczy
źródło
Dodatkowo do odpowiedzi @Bothwells (którą wolę) dla pojedynczych wartości, w celu sprawdzenia zerowego przypisania wartości zwracanych przez funkcję, możesz użyć nowego operatora morsa (od python3.8):
Dlatego
test
funkcja nie musi być oceniana dwa razy (jak wa = 2 if test() is None else test()
)źródło
W przypadku potrzeby zagnieżdżenia więcej niż jednej zerowej operacji koalescencji, takiej jak:
model?.data()?.first()
Nie jest to problem łatwy do rozwiązania
or
. Nie można go również rozwiązać za.get()
pomocą typu słownika lub podobnego (i tak nie można go zagnieżdżić) lubgetattr()
który zgłosi wyjątek, gdy NoneType nie ma atrybutu.Odpowiednim pipem rozważającym dodanie koalescencji zerowej do języka jest PEP 505, a dyskusja dotycząca dokumentu znajduje się w wątku python-ideas .
źródło
Odnośnie odpowiedzi @Hugh Bothwell, @mortehu i @glglgl.
Skonfiguruj zestaw danych do testowania
Zdefiniuj implementacje
Włącz funkcję testową
Wyniki na komputerze Mac i7 @ 2.7 Ghz przy użyciu języka Python 2.7
Oczywiście
not_none
funkcja poprawnie odpowiada na pytanie OP i radzi sobie z problemem „falsy”. Jest to również najszybszy i najłatwiejszy do odczytania. Jeśli zastosujesz logikę w wielu miejscach, jest to zdecydowanie najlepsza droga.Jeśli masz problem, w którym chcesz znaleźć pierwszą wartość inną niż null w iterowalnym, odpowiedź @ mortehu jest dobrym rozwiązaniem. Ale jest to rozwiązanie innego problemu niż OP, chociaż może częściowo poradzić sobie z tą sprawą. Nie może przyjąć iterowalnej ORAZ wartości domyślnej. Ostatnim argumentem byłaby zwrócona wartość domyślna, ale w takim przypadku nie przekazano by się iterowalnego, a także nie jest jasne, że ostatni argument jest wartością domyślną.
Możesz wtedy zrobić poniżej, ale nadal używałbym
not_null
dla przypadku użycia pojedynczej wartości.źródło
Dla takich jak ja, którzy natknęli się tutaj, szukając realnego rozwiązania tego problemu, kiedy zmienna może być niezdefiniowana, najbliższe, jakie mam, to:
Zwróć uwagę, że podczas sprawdzania wartości globalnych potrzebny jest ciąg, ale później podczas sprawdzania wartości używana jest rzeczywista zmienna.
Więcej informacji o istnieniu zmiennych: Jak sprawdzić, czy zmienna istnieje?
źródło
(variablename or False) == True
jest taki sam jakvariablename == True
jeśli nie możesz znaleźć nazwy w słowniku, zwróci wartość domyślną, jeśli nazwa istnieje, doda dowolną istniejącą wartość z 1.
mam nadzieję, że to może pomóc
źródło
Dwie poniższe funkcje okazały się bardzo przydatne w przypadku wielu zmiennych przypadków testowych.
źródło