Jak zmienić wartość w Pythonie


Odpowiedzi:


273

Rozwiązanie wykorzystujące NOT

Jeśli wartości są logiczne, najszybszym podejściem jest użycie operatora not :

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

Rozwiązanie za pomocą odejmowania

Jeśli wartości są liczbowe, odejmowanie od sumy jest prostym i szybkim sposobem przełączania wartości:

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

Rozwiązanie wykorzystujące XOR

Jeśli wartość przełącza się między 0 a 1 , możesz użyć bitowego wyłącznika lub :

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

Technika uogólnia się na dowolną parę liczb całkowitych. Xor-by-one step jest zastępowany przez xor-by-precomputed-fixed:

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

(Pomysł został zgłoszony przez Nicka Coghlana, a później uogólniony przez @zxxc).

Rozwiązanie za pomocą słownika

Jeśli wartości są hashable, możesz użyć słownika:

>>> 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'

Rozwiązanie wykorzystujące wyrażenie warunkowe

Najwolniejszym sposobem jest użycie wyrażenia warunkowego :

>>> 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]

Rozwiązanie wykorzystujące itertools

Jeśli masz więcej niż dwie wartości, funkcja itertools.cycle () zapewnia ogólny, szybki sposób przełączania między kolejnymi wartościami:

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

Zauważ, że w Pythonie 3 next()metoda została zmieniona na __next__(), więc pierwsza linia byłaby teraz zapisana jakotoggle = itertools.cycle(['red', 'green', 'blue']).__next__


Ostatni przykład wydaje się tak sprytny i intuicyjny, ale nie działa w Pythonie 3+ po usunięciu .next (). Czy istnieje sposób, aby działał podobnie w późniejszej wersji Pythona?
labarna

2
@labarna W Pythonie 3 .next()zastąpiono funkcję globalną next(). Powyższy przykład to:toggle = itertools.cycle(...); next(toggle)
elpres

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

7
Przykład XOR można uogólnić, aby przełączać między wartościami ai bużywać x = x ^ (a ^ b).
zxxc

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

33

Zawsze używam:

p^=True

Jeśli p jest wartością logiczną, przełącza się między prawdą a fałszem.


1
Idealny! pnie trzeba odwoływać się dwa razy, aby ta metoda działała !! Pomysł, jeśli przełączasz wartość z długą długą referencją.
ThorSummoner

1
jak nazywa się ten operator?
mix3d

4
To jest operator XOR.
bastelflp

1
@ mix3d Dokładnie jest to „wyłączne bitowo lub” (w przeciwieństwie do „wyłączne logiczne” lub) - wiki.python.org/moin/BitwiseOperators . Logiczny XOR nie ma ogólnie określonego operatora w Pythonie, ale można go znaleźć w niektórych specjalnych przypadkach, takich jak moduł dziesiętny.
Taylor Edmiston

@ mix3d ^=to bitowe przypisanie xor
wjandrea

23

Oto inny nieintuicyjny sposób. Piękno polega na tym, że możesz zmieniać wiele wartości, a nie tylko dwie [0,1]

Dla dwóch wartości (przełączanie)

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

Dla wielu wartości (powiedzmy 4)

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

Nie spodziewałem się, że to rozwiązanie będzie też prawie najszybsze

>>> 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
tak, to jest schweet jak orzech. dzięki wszystkim, fajnie jest patrzeć, jak różni ludzie podchodzą do problemu (i pouczające).

Fajnie, to miniaturowa maszyna stanowa.
kindall

cóż, twój jest najciekawszy, ale nie jest to to, czego osobiście potrzebuję do tego, o co pytałem, więc ok, myślę, że prosta matematyka jest wtedy prawdopodobnie najlepsza dla mnie, czy nie powinno tam być 1-x?

Tak, ale to nie powinno zmieniać prędkości.
Blender

ai, ale to by było złe, prawda? kilka świetnych odpowiedzi tutaj, TAK rządzi!

19

notOperator neguje zmienną (przekształcenie go w logiczną, jeśli nie jest już jeden). Prawdopodobnie możesz używać 1i 0zamiennie z Truei False, więc po prostu zaneguj to:

toggle = not toggle

Ale jeśli używasz dwóch dowolnych wartości, użyj inline if:

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

1
+1, ale toggle = 0 if toggle else 1jest krótszy i bardziej ogólny
luc

Przepraszam, zamienię zmienne, żeby było jaśniej. Używałem inline ifdo przełączania się między dwiema dowolnymi zmiennymi, a nie tylko 1i 0.
Blender

14

Tylko między 1 a 0, zrób to

1-x 

x może przyjąć 1 lub 0


Ponieważ (w każdym razie w Pythonie 2.x) Truei Falsesą w rzeczywistości liczbami całkowitymi, chociaż te z zaskakująco rozwlekłą __str__()metodą, xmogą również być Truelub Falsetutaj. Otrzymasz jednak 1 lub 0 z powrotem.
kindall


7

Zaskakujące jest, że nikt nie wspomniał starego dobrego podziału 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

Zauważ, że jest to równoważne x = x - 1, ale zaletą techniki modulo jest to, że rozmiar grupy lub długość interwału może być większy niż tylko 2 elementy, dając w ten sposób schemat przeplotu podobnego do okrężnego.

Teraz tylko dla 2, przełączanie może być nieco krótsze (używając operatora bitowego):

x = x ^ 1

Nie jestem pewien, jak „pythoniczny” jest to (podobna do C) arytmetyka modulo (tj. Czy „pythonic” ma zastosowanie?). Myślę, że to tylko arytmetyka, działa wszędzie tam, gdzie masz binarny.
Yauhen Yakimovich

Oczywiście maszyna skończonych stanów z krotką taką jak x = (1,2,3,0); token = 0; token = x [token] jest niezwykle ekscytujący, ponieważ może być nawet bardziej ogólny niż tylko operacja grupowa.
Yauhen Yakimovich

7

jednym ze sposobów przełączania jest użycie przypisania wielokrotnego

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

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

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

Korzystanie z 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

Najłatwiejszym sposobem przełączania się między 1 a 0 jest odjęcie od 1.

def toggle(value):
    return 1 - value

4

Korzystanie z obsługi wyjątków

>>> 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, jestem najgorszy:

wprowadź opis obrazu tutaj

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

A co z wyimaginowanym przełącznikiem, który przechowuje nie tylko bieżący przełącznik, ale kilka innych powiązanych z nim wartości?

toggle = complex.conjugate

Przechowuj dowolną wartość + lub - po lewej stronie i każdą wartość bez znaku po prawej:

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

Zero też działa:

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

Łatwo pobierz bieżącą wartość przełączania ( Truei Falsereprezentuj + i -), wartość LHS (rzeczywistą) lub RHS (urojoną):

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

Łatwo zamień LHS i RHS (ale pamiętaj, że znak obu wartości nie może być ważny):

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

Łatwo zamień LHS i RHS, a także przełączaj w tym samym czasie:

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

Ochrona przed błędami:

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

Wykonaj zmiany w LHS i RHS:

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

... ale zachowaj ostrożność przy manipulowaniu RHS:

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

2

Zmienne a i b mogą mieć DOWOLNE dwie wartości, takie jak 0 i 1 lub 117 i 711 lub „orła” i „reszka”. Nie używa się matematyki, tylko szybka zamiana wartości za każdym razem, gdy wymagane jest przełączenie.

a = True   
b = False   

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

1

Używam funkcji abs, bardzo przydatnej na pętlach

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

x będzie równe 0.


0

Zróbmy hakowanie ramek. Przełącz zmienną według nazwy. Uwaga: to może nie działać w każdym środowisku wykonawczym Pythona.

Powiedzmy, że masz zmienną „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

Jeśli masz do czynienia ze zmienną całkowitą, możesz zwiększyć 1 i ograniczyć swój zestaw do 0 i 1 (mod)

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

0

Przełączanie między -1 a +1 można uzyskać przez mnożenie w wierszu; stosowany do obliczania liczby pi metodą „Leibniza” (lub podobną):

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

0

Możesz skorzystać indexz lists.

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"

Zalety : brak dodatkowych bibliotek, samowyjaśnienia kodu i praca z dowolnymi typami danych.

Wady : nie zapisuj duplikatów. toggleValues(["one","two","duped", "three", "duped", "four"], "duped") zawsze wróci"three"

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.