How to toggle a value in Python
在
解决方案使用不
如果值是布尔值,则最快的方法是使用not运算符:
1 2 3 4 5 6 7 8 9 10 | >>> x = True >>> x = not x # toggle >>> x False >>> x = not x # toggle >>> x True >>> x = not x # toggle >>> x False |
用减法求解
如果值是数字,则从总计中减去是切换值的简单快速方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 | >>> 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 |
使用XOR的解决方案
如果该值在0和1之间切换,则可以使用按位异或:
1 2 3 4 5 6 7 | >>> x = 1 >>> x ^= 1 >>> x 0 >>> x ^= 1 >>> x 1 |
该技术推广到任何整数对。一个步骤的xor被预先计算的常量替换为xor:
1 2 3 4 5 6 7 8 9 10 11 12 13 | >>> 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 |
(这个想法是由Nick Coghlan提出的,后来由@zxxc推广。)
使用字典的解决方案如果值是可哈希的,则可以使用字典:
1 2 3 4 5 6 7 8 9 10 11 12 13 | >>> 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' |
使用条件表达式的解决方案
最慢的方法是使用条件表达式:
1 2 3 4 5 6 7 8 9 10 11 12 | >>> 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] |
使用itertools的解决方案
如果您有两个以上的值,itertools.cycle()函数提供了一种在连续值之间切换的通用快速方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | >>> import itertools >>> toggle = itertools.cycle(['red', 'green', 'blue']).next >>> toggle() 'red' >>> toggle() 'green' >>> toggle() 'blue' >>> toggle() 'red' >>> toggle() 'green' >>> toggle() 'blue' |
注意,在python 3中,
我总是使用:
1 | p^=True |
如果p是一个布尔值,那么它将在true和false之间切换。
这是另一种非直觉的方式。美丽的是你可以在多个值上循环,而不仅仅是两个[0,1]
对于两个值(切换)
1 2 | >>> x=[1,0] >>> toggle=x[toggle] |
对于多个值(比如4)
1 2 | >>> x=[1,2,3,0] >>> toggle=x[toggle] |
我没想到这个解决方案也几乎是最快的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | >>> 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 | toggle = not toggle |
但是,如果使用两个任意值,请使用内联
1 | toggle = 'a' if toggle == 'b' else 'b' |
在1到0之间,执行此操作
1 | 1-x |
X可以取1或0
三角法,因为
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | >>> import math >>> def generator01(): ... n=0 ... while True: ... yield abs( int( math.cos( n * 0.5 * math.pi ) ) ) ... n+=1 ... >>> g=generator01() >>> g.next() 1 >>> g.next() 0 >>> g.next() 1 >>> g.next() 0 |
令人惊讶的是,没有人提到好的旧除法模2:
1 2 3 4 5 6 7 8 9 10 11 | 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 |
注意,它相当于
现在,仅对于2,切换可以稍微短一点(使用逐位运算符):
1 | x = x ^ 1 |
切换的一种方法是使用多个分配
1 2 3 4 5 6 7 8 9 10 | >>> a = 5 >>> b = 3 >>> t = a, b = b, a >>> t[0] 3 >>> t = a, b = b, a >>> t[0] 5 |
使用itertools:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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 |
在1和0之间切换的最简单方法是从1中减去。
1 2 | def toggle(value): return 1 - value |
使用异常处理程序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | >>> 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 |
好吧,我是最坏的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | 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" ", f.func_name x=0 for _ in range(0,100000000): x=f(x) |
一个假想的开关,它不仅存储当前的开关,而且存储一些与之相关联的其他值,怎么样?
1 | toggle = complex.conjugate |
在左侧存储任意+或-值,在右侧存储任意无符号值:
1 2 3 | >>> x = 2 - 3j >>> toggle(x) (2+3j) |
同样,零功:
1 2 3 | >>> y = -2 - 0j >>> toggle(y) (-2+0j) |
轻松检索当前切换值(
1 2 3 4 5 6 7 8 9 10 11 | >>> 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 |
轻松交换左、右(但请注意,这两个值的符号一定不重要):
1 2 3 4 5 | >>> swap = lambda i: i/-1j >>> swap(2+0j) 2j >>> swap(3+2j) (2+3j) |
可轻松交换左侧和右侧,同时切换:
1 2 3 4 5 | >>> swaggle = lambda i: i/1j >>> swaggle(2+0j) -2j >>> swaggle(3+2j) (2-3j) |
防止错误:
1 2 3 4 | >>> toggle(1) Traceback (most recent call last): File"<stdin>", line 1, in <module> TypeError: descriptor 'conjugate' requires a 'complex' object but received a 'int' |
对左侧和右侧进行更改:
1 2 3 | >>> x += 1+2j >>> x (3+5j) |
…但小心操纵右侧:
1 2 3 4 | >>> z = 1-1j >>> z += 2j >>> z (1+1j) # whoops! toggled it! |
我使用abs函数,在循环上非常有用
1 2 3 | x = 1 for y in range(0, 3): x = abs(x - 1) |
X将是0。
变量A和B可以是任意两个值,如0和1,或117和711,或"heads"和"tails"。不使用数学,只需在每次需要切换时快速交换值。
1 2 3 4 5 | a = True b = False a,b = b,a # a is now False a,b = b,a # a is now True |
在-1和+1之间的切换可以通过内联乘法获得;用于"leibniz"方式(或类似方式)计算pi:
1 2 3 4 5 6 | sign = 1 result = 0 for i in range(100000): result += 1 / (2*i + 1) * sign sign *= -1 print("pi (estimate):", result*4) |
让我们来做一些框架黑客。按名称切换变量。注意:这可能不适用于每个Python运行时。
假设你有一个变量"x"
1 2 3 4 5 6 7 8 9 10 11 12 13 | >>> 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 |
如果处理的是整数变量,则可以增加1,并将设置限制为0和1(mod)
1 2 | X = 0 # or X = 1 X = (X + 1)%2 |