So schalten Sie einen Wert in Python um


Antworten:


272

Lösung mit NOT

Wenn die Werte boolesch sind, besteht der schnellste Ansatz darin, den Operator not zu verwenden :

>>> x = True
>>> x = not x        # toggle
>>> x
False
>>> x = not x        # toggle
>>> x
True
>>> x = not x        # toggle
>>> x
False

Lösung mit Subtraktion

Wenn die Werte numerisch sind, ist die Subtraktion von der Summe eine einfache und schnelle Möglichkeit, Werte umzuschalten:

>>> A = 5
>>> B = 3
>>> total = A + B
>>> x = A
>>> x = total - x    # toggle
>>> x
3
>>> x = total - x    # toggle
>>> x
5
>>> x = total - x    # toggle
>>> x
3

Lösung mit XOR

Wenn der Wert zwischen 0 und 1 wechselt , können Sie ein bitweises Exklusiv-Oder verwenden :

>>> x = 1
>>> x ^= 1
>>> x
0
>>> x ^= 1
>>> x
1

Die Technik verallgemeinert sich auf ein beliebiges Paar von ganzen Zahlen. Der xor-by-one-Schritt wird durch eine xor-by-vorberechnete Konstante ersetzt:

>>> A = 205
>>> B = -117
>>> t = A ^ B        # precomputed toggle constant
>>> x = A
>>> x ^= t           # toggle
>>> x
-117
>>> x ^= t           # toggle
>>> x
205
>>> x ^= t           # toggle
>>> x
-117

(Diese Idee wurde von Nick Coghlan eingereicht und später von @zxxc verallgemeinert.)

Lösung mit einem Wörterbuch

Wenn die Werte hashbar sind, können Sie ein Wörterbuch verwenden:

>>> A = 'xyz'
>>> B = 'pdq'
>>> d = {A:B, B:A}
>>> x = A
>>> x = d[x]         # toggle
>>> x
'pdq'
>>> x = d[x]         # toggle
>>> x
'xyz'
>>> x = d[x]         # toggle
>>> x
'pdq'

Lösung unter Verwendung eines bedingten Ausdrucks

Der langsamste Weg ist die Verwendung eines bedingten Ausdrucks :

>>> A = [1,2,3]
>>> B = [4,5,6]
>>> x = A
>>> x = B if x == A else A
>>> x
[4, 5, 6]
>>> x = B if x == A else A
>>> x
[1, 2, 3]
>>> x = B if x == A else A
>>> x
[4, 5, 6]

Lösung mit itertools

Wenn Sie mehr als zwei Werte haben, bietet die Funktion itertools.cycle () eine generische schnelle Möglichkeit, zwischen aufeinanderfolgenden Werten umzuschalten :

>>> import itertools
>>> toggle = itertools.cycle(['red', 'green', 'blue']).next
>>> toggle()
'red'
>>> toggle()
'green'
>>> toggle()
'blue'
>>> toggle()
'red'
>>> toggle()
'green'
>>> toggle()
'blue'

Beachten Sie, dass in Python 3 die next()Methode in geändert wurde __next__(), sodass die erste Zeile jetzt als geschrieben wirdtoggle = itertools.cycle(['red', 'green', 'blue']).__next__


Das letzte Beispiel scheint so schick und intuitiv zu sein, funktioniert aber in Python 3+ nicht, wenn .next () entfernt wird. Gibt es eine Möglichkeit, es in einer späteren Version von Python ähnlich zu machen?
Labarna

2
@labarna In Python 3 wurde das .next()durch eine globale next()Funktion ersetzt. Das obige Beispiel wäre:toggle = itertools.cycle(...); next(toggle)
Elpres

2
toggle = itertools.cycle(['red', 'green', 'blue']) next(toggle)
Maximilian

7
Das XOR-Beispiel kann verallgemeinert werden, um zwischen Werten aund bVerwendung umzuschalten x = x ^ (a ^ b).
zxxc

int(not 0)und int(not 1)... hrmmm
jhrr

33

Ich benutze immer:

p^=True

Wenn p ein Boolescher Wert ist, wird zwischen true und false umgeschaltet.


1
Perfekt! pmuss nicht zweimal referenziert werden, damit diese Methode funktioniert !! Idee, wenn Sie einen Wert mit einer langen langen Referenz umschalten.
ThorSummoner

1
Wie heißt dieser Operator?
mix3d

4
Dies ist der XOR-Operator.
Bastelflp

1
@ mix3d Genau genommen ist es "bitweise exklusiv oder" (im Gegensatz zu "logisch exklusiv oder") - wiki.python.org/moin/BitwiseOperators . Logisches XOR hat in Python im Allgemeinen keinen bestimmten Operator, aber Sie können ihn in einigen speziellen Fällen wie im Dezimalmodul implementieren .
Taylor Edmiston

@ mix3d ^=ist bitweise xor Zuordnung
wjandrea

23

Hier ist ein anderer nicht intuitiver Weg. Das Schöne ist, dass Sie über mehrere Werte fahren können und nicht nur über zwei [0,1]

Für zwei Werte (Umschalten)

>>> x=[1,0]
>>> toggle=x[toggle]

Für mehrere Werte (sagen wir 4)

>>> x=[1,2,3,0]
>>> toggle=x[toggle]

Ich hatte nicht erwartet, dass diese Lösung auch fast die schnellste sein würde

>>> stmt1="""
toggle=0
for i in xrange(0,100):
    toggle = 1 if toggle == 0 else 0
"""
>>> stmt2="""
x=[1,0]
toggle=0
for i in xrange(0,100):
    toggle=x[toggle]
"""
>>> t1=timeit.Timer(stmt=stmt1)
>>> t2=timeit.Timer(stmt=stmt2)
>>> print "%.2f usec/pass" % (1000000 * t1.timeit(number=100000)/100000)
7.07 usec/pass
>>> print "%.2f usec/pass" % (1000000 * t2.timeit(number=100000)/100000)
6.19 usec/pass
stmt3="""
toggle = False
for i in xrange(0,100):
    toggle = (not toggle) & 1
"""
>>> t3=timeit.Timer(stmt=stmt3)
>>> print "%.2f usec/pass" % (1000000 * t3.timeit(number=100000)/100000)
9.84 usec/pass
>>> stmt4="""
x=0
for i in xrange(0,100):
    x=x-1
"""
>>> t4=timeit.Timer(stmt=stmt4)
>>> print "%.2f usec/pass" % (1000000 * t4.timeit(number=100000)/100000)
6.32 usec/pass

1
Ja, das ist schweet als Nuss.

Schön, es ist eine Miniatur-Zustandsmaschine.
Kindall

Nun, dein ist das interessanteste, aber es ist nicht das, was ich persönlich für das, was ich gefragt habe, brauche. Also ok, ich denke, das einfache mathematische ist dann wahrscheinlich das beste für mich, sollte das nicht 1-x sein?

Ja, aber das sollte die Geschwindigkeit nicht anders machen.
Blender

ai, aber es würde es falsch machen, nicht wahr? Einige großartige Antworten hier, SO rockt!

19

Der notOperator negiert Ihre Variable (konvertiert sie in einen Booleschen Wert, falls dies noch nicht geschehen ist). Sie können wahrscheinlich verwenden 1und 0austauschbar mit Trueund False, so ist es einfach zu negieren:

toggle = not toggle

Wenn Sie jedoch zwei beliebige Werte verwenden, verwenden Sie eine Inline if:

toggle = 'a' if toggle == 'b' else 'b'

1
+1 aber toggle = 0 if toggle else 1ist kürzer und allgemeiner
luc

Entschuldigung, ich werde Variablen austauschen, um es klarer zu machen. Ich habe die Inline verwendet, ifum zwischen zwei beliebigen Variablen umzuschalten, nicht nur 1und 0.
Blender

14

Tun Sie dies nur zwischen 1 und 0

1-x 

x kann 1 oder 0 annehmen


Da (in Python 2.x jedenfalls) Trueund Falseeigentlich ganze Zahlen sind, wenn auch solche mit einer überraschend ausführlichen __str__()Methode, xkönnen auch Trueoder Falsehier sein. Sie erhalten jedoch 1 oder 0 zurück.
Kindall


7

Überraschenderweise erwähnt niemand die gute alte Division Modulo 2:

In : x = (x + 1)  % 2 ; x
Out: 1

In : x = (x + 1)  % 2 ; x
Out: 0

In : x = (x + 1)  % 2 ; x
Out: 1

In : x = (x + 1)  % 2 ; x
Out: 0

Beachten Sie, dass dies äquivalent zu x = x - 1ist, der Vorteil der Modulo-Technik jedoch darin besteht, dass die Größe der Gruppe oder die Länge des Intervalls größer als nur 2 Elemente sein kann, sodass Sie ein ähnliches Round-Robin-Interleaving-Schema zum Schleifen erhalten.

Nur für 2 kann das Umschalten etwas kürzer sein (mit dem bitweisen Operator):

x = x ^ 1

Ich bin nicht sicher, wie "pythonisch" diese (C-ähnliche) Modulo-Arithmetik ist (d. H. Ob "pythonisch" gilt?). Ich denke, es ist nur Arithmetik, funktioniert überall, wo Sie Binär haben.
Yauhen Yakimovich

Offensichtlich ist die Finite-State-Maschine mit einem Tupel wie x = (1,2,3,0); token = 0; token = x [token] ist äußerst aufregend, da es noch allgemeiner sein kann als nur eine Gruppenoperation.
Yauhen Yakimovich

7

Eine Möglichkeit zum Umschalten ist die Verwendung der Mehrfachzuweisung

>>> a = 5
>>> b = 3

>>> t = a, b = b, a
>>> t[0]
3

>>> t = a, b = b, a
>>> t[0]
5

Verwenden von itertools:

In [12]: foo = itertools.cycle([1, 2, 3])

In [13]: next(foo)
Out[13]: 1

In [14]: next(foo)
Out[14]: 2

In [15]: next(foo)
Out[15]: 3

In [16]: next(foo)
Out[16]: 1

In [17]: next(foo)
Out[17]: 2

4

Der einfachste Weg, zwischen 1 und 0 umzuschalten, ist das Subtrahieren von 1.

def toggle(value):
    return 1 - value

4

Ausnahmebehandler verwenden

>>> def toogle(x):
...     try:
...         return x/x-x/x
...     except  ZeroDivisionError:
...         return 1
... 
>>> x=0
>>> x=toogle(x)
>>> x
1
>>> x=toogle(x)
>>> x
0
>>> x=toogle(x)
>>> x
1
>>> x=toogle(x)
>>> x
0

Ok, ich bin das Schlimmste:

Geben Sie hier die Bildbeschreibung ein

import math
import sys

d={1:0,0:1}
l=[1,0]

def exception_approach(x):
    try:
        return x/x-x/x
    except  ZeroDivisionError:
        return 1

def cosinus_approach(x):
    return abs( int( math.cos( x * 0.5 * math.pi  ) ) )

def module_approach(x):
    return  (x + 1)  % 2

def subs_approach(x):
    return  x - 1

def if_approach(x):
    return 0 if x == 1 else 1

def list_approach(x):
    global l
    return l[x]

def dict_approach(x):
    global d
    return d[x]

def xor_approach(x):
    return x^1

def not_approach(x):
    b=bool(x)
    p=not b
    return int(p)

funcs=[ exception_approach, cosinus_approach, dict_approach, module_approach, subs_approach, if_approach, list_approach, xor_approach, not_approach ]

f=funcs[int(sys.argv[1])]
print "\n\n\n", f.func_name
x=0
for _ in range(0,100000000):
    x=f(x)

3

Wie wäre es mit einem imaginären Umschalter, der nicht nur den aktuellen Umschalter, sondern auch einige andere damit verbundene Werte speichert?

toggle = complex.conjugate

Speichern Sie einen beliebigen + oder - Wert links und einen beliebigen Wert ohne Vorzeichen rechts:

>>> x = 2 - 3j
>>> toggle(x)
(2+3j)

Null funktioniert auch:

>>> y = -2 - 0j
>>> toggle(y)
(-2+0j)

Rufen Sie einfach den aktuellen Umschaltwert ab ( Trueund Falsestellen Sie + und - dar), den LHS-Wert (real) oder den RHS-Wert (imaginär):

>>> import math
>>> curr = lambda i: math.atan2(i.imag, -abs(i.imag)) > 0
>>> lhs = lambda i: i.real
>>> rhs = lambda i: abs(i.imag)
>>> x = toggle(x)
>>> curr(x)
True
>>> lhs(x)
2.0
>>> rhs(x)
3.0

Tauschen Sie einfach LHS und RHS aus (beachten Sie jedoch, dass das Vorzeichen der beiden Werte nicht wichtig sein darf):

>>> swap = lambda i: i/-1j
>>> swap(2+0j)
2j
>>> swap(3+2j)
(2+3j)

Tauschen Sie einfach LHS und RHS aus und schalten Sie gleichzeitig um:

>>> swaggle = lambda i: i/1j
>>> swaggle(2+0j)
-2j
>>> swaggle(3+2j)
(2-3j)

Schutz vor Fehlern:

>>> toggle(1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: descriptor 'conjugate' requires a 'complex' object but received a 'int'

Führen Sie Änderungen an LHS und RHS durch:

>>> x += 1+2j
>>> x
(3+5j)

... aber seien Sie vorsichtig beim Manipulieren der RHS:

>>> z = 1-1j
>>> z += 2j
>>> z
(1+1j) # whoops! toggled it!

2

Die Variablen a und b können JEDE zwei Werte sein, wie 0 und 1 oder 117 und 711 oder "Köpfe" und "Schwänze". Es wird keine Mathematik verwendet, nur ein schneller Austausch der Werte jedes Mal, wenn ein Umschalten gewünscht wird.

a = True   
b = False   

a,b = b,a   # a is now False
a,b = b,a   # a is now True

1

Ich benutze die abs-Funktion, sehr nützlich bei Loops

x = 1
for y in range(0, 3):
    x = abs(x - 1)

x wird 0 sein.


0

Lassen Sie uns ein paar Frame-Hacking machen. Schalten Sie eine Variable nach Namen um. Hinweis: Dies funktioniert möglicherweise nicht mit jeder Python-Laufzeit.

Angenommen, Sie haben eine Variable "x"

>>> import inspect
>>> def toggle(var_name):
>>>     frame = inspect.currentframe().f_back
>>>     vars = frame.f_locals
>>>     vars[var_name] = 0 if vars[var_name] == 1 else 1

>>> x = 0
>>> toggle('x')
>>> x
1
>>> toggle('x')
>>> x
0

0

Wenn Sie es mit einer ganzzahligen Variablen zu tun haben, können Sie 1 erhöhen und Ihre Menge auf 0 und 1 (mod) beschränken.

X = 0  # or X = 1
X = (X + 1)%2

0

Das Umschalten zwischen -1 und +1 kann durch Inline-Multiplikation erfolgen. wird zur Berechnung von pi nach 'Leibniz'-Art (oder ähnlich) verwendet:

sign = 1
result = 0
for i in range(100000):
    result += 1 / (2*i + 1) * sign
    sign *= -1
print("pi (estimate): ", result*4)

0

Sie können die indexvon lists verwenden.

def toggleValues(values, currentValue):
    return values[(values.index(currentValue) + 1) % len(values)]

> toggleValues( [0,1] , 1 )
> 0
> toggleValues( ["one","two","three"] , "one" )
> "two"
> toggleValues( ["one","two","three"] , "three")
> "one"

Pros : Keine zusätzlichen Bibliotheken, self.explanatory Code und arbeitet mit beliebigen Datentypen.

Nachteile : nicht doppelt speichern. toggleValues(["one","two","duped", "three", "duped", "four"], "duped") wird immer wiederkommen"three"

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.