Hat Python eine "oder gleich" -Funktion wie || = in Ruby?

82

Wenn nicht, wie geht das am besten?

Im Moment mache ich (für ein Django-Projekt):

if not 'thing_for_purpose' in request.session:
    request.session['thing_for_purpose'] = 5

aber es ist ziemlich umständlich. In Ruby wäre es:

request.session['thing_for_purpose'] ||= 5

das ist viel schöner.

Sean W.
quelle
23
Beachten Sie, dass diese beiden Codebits tatsächlich sehr unterschiedlich sind: Die Python-Version setzt sie auf 5, wenn sie überhaupt nicht im Diktat enthalten ist, während die Ruby-Version sie auch auf 5 setzt, wenn sie auf einen falschen Wert gesetzt ist.
Glenn Maynard
2
@Glenn, nicht sehr unterschiedlich, aber ganz anders. Da ein nicht initialisierter Hashwert zurückgegeben wird nil(false im booleschen Kontext), wird diese Redewendung häufig genau für den Zweck verwendet, den sean verwendet hat. Das Idiom funktioniert nur , wenn , wenn, natürlich, nilund falsesind nicht legitim Werte in der Hash (was sehr häufig der Fall ist, so das Idiom in Ordnung ist)
horseyguy
8
@banister: Ich weiß nicht, wo man die Grenze zwischen "sehr" und "ganz" ziehen könnte, aber der Punkt ist, dass dies keine äquivalenten Aussagen sind und es wichtig ist, den Unterschied zu verstehen. (False ist sehr oft ein gültiger Wert in einem Hash, der Sie beißt, wenn Sie einen Standardwert für ein boolesches Feld auf true setzen möchten. Dies ist ein erheblicher Mangel an Rubys Redewendung.)
Glenn Maynard
Ja, das Python-Beispiel ähnelt eher dem definierten oder , wie //=Sie es in Perl finden . Ich denke das kommt ||=auch von Perl.
Draegtun
Ah, gute Punkte, alle. Ich hatte diesen Unterschied nicht bemerkt.
Sean W.

Antworten:

187

Die akzeptierte Antwort ist gut für Diktate, aber der Titel sucht ein allgemeines Äquivalent zu Rubys || = Operator. Ein üblicher Weg, um etwas wie || = in Python zu tun, ist

x = x or new_value
Joseph Sheedy
quelle
36
Diese Antwort ist wahrscheinlich das, wonach die Leute suchen, die von einer Google-Suche hierher kommen.
Gradi3nt
Das ist wirklich die beste Antwort.
AdamC
6
Beachten Sie, dass dieser Code im Gegensatz zu Ruby nur funktioniert, wenn xer zuvor definiert wurde (z. B. Nonein einer Klasseninitialisierungsmethode festgelegt).
Oli
3
Dies verhält sich zwar nicht genau wie Rubys || =. Eine andere Sache, auf die man achten sollte, ist die 'Wahrhaftigkeit' von x. Wenn x == 0 in Python, erhalten Sie new_value, da 0 als falsch angesehen wird, aber in Ruby erhalten Sie 0.
Joseph Sheedy
1
Ist das so effizient wie || =? || = führt keine Zuweisung durch, es sei denn, es ist null, aber dies führt immer eine Zuweisung durch. Ist der Python-Compiler schlauer als ich denke?
Jsarma
17

dicthat setdefault().

Also wenn request.sessionist ein dict:

request.session.setdefault('thing_for_purpose', 5)
Jon-Eric
quelle
Vage ähnlich, aber in keiner Weise das Äquivalent von Rubys || =.
AdamC
1
Es unterscheidet sich erheblich darin, dass der Standardausdruck auch dann ausgewertet wird, wenn der Schlüssel bereits festgelegt ist. Es gibt keine Möglichkeit, die ursprüngliche Frage zu lösen, ohne entweder den Standardwert auszuwerten oder mehrmals auf den Schlüssel zuzugreifen oder beides.
Slinkp
11

Präzise Antwort: Nein. Python verfügt nicht über einen einzigen integrierten Operator op, in den übersetzt x = x or ywerden kann x op y.

Aber es tut es fast. Der bitweise oder gleich Operator ( |=) wird wie oben beschrieben funktionieren , wenn beide Operanden als Boolesche Werte behandelt werden, mit einem Vorbehalt. (Was ist die Einschränkung? Die Antwort ist natürlich unten.)

Zunächst die grundlegende Demonstration der Funktionalität:

x = True
x    
Out[141]: True

x |= True
x    
Out[142]: True

x |= False
x    
Out[143]: True

x &= False
x    
Out[144]: False

x &= True
x    
Out[145]: False

x |= False
x    
Out[146]: False

x |= True
x   
Out[147]: True

Die Einschränkung ist darauf zurückzuführen, dass Python nicht streng typisiert ist. Selbst wenn die Werte in einem Ausdruck als Boolesche Werte behandelt werden, werden sie nicht kurzgeschlossen, wenn sie einem bitweisen Operator zugewiesen werden. Angenommen, wir hatten eine boolesche Funktion, die eine Liste löscht und zurückgibt, Truewenn Elemente gelöscht wurden:

def  my_clear_list(lst):
    if not lst:
        return False
    else:
        del lst[:]
        return True

Jetzt können wir das kurzgeschlossene Verhalten so sehen:

x = True
lst = [1, 2, 3]
x = x or my_clear_list(lst)
print(x, lst)

Output: True [1, 2, 3]

Wenn Sie jedoch orauf bitweise oder ( |) umschalten , wird der Kurzschluss behoben, sodass die Funktion my_clear_listausgeführt wird.

x = True
lst = [1, 2, 3]
x = x | my_clear_list(lst)
print(x, lst)

Output: True []

Oben x = x | my_clear_list(lst)ist äquivalent zu x |= my_clear_list(lst).

Apollys unterstützt Monica
quelle
10

Das Festlegen eines Standardwerts ist sinnvoll, wenn Sie dies in einer Middleware oder Ähnlichem tun, wenn Sie jedoch einen Standardwert im Kontext einer Anforderung benötigen:

request.session.get('thing_for_purpose', 5) # gets a default

Bonus: Hier erfahren Sie, wie Sie wirklich ||=in Python arbeiten.

def test_function(self, d=None):
    'a simple test function'
    d = d or {}

    # ... do things with d and return ...
Brian Hicks
quelle
1

Im Allgemeinen können Sie verwenden dict[key] = dict.get(key, 0) + val.

Curtissv
quelle