你如何在Python中获得两个变量的逻辑xor?
例如,我有两个我期望成为字符串的变量.我想测试只有其中一个包含True值(不是None或空字符串):
str1 = raw_input("Enter string one:") str2 = raw_input("Enter string two:") if logical_xor(str1, str2): print "ok" else: print "bad"
该^
运营商似乎是按位,并在所有对象没有定义:
>>> 1 ^ 1 0 >>> 2 ^ 1 3 >>> "abc" ^ "" Traceback (most recent call last): File "", line 1, in TypeError: unsupported operand type(s) for ^: 'str' and 'str'
A. Coady.. 1113
如果你已经将输入规范化为布尔值,那么!=是xor.
bool(a) != bool(b)
虽然这很聪明而且简短,但我不相信它很干净.当有人在代码中读取此构造时,对于他们来说,这是一个xor操作吗?我觉得有必要添加评论 - 这对我来说是一个标志,我写的代码不清楚,并试着用评论道歉. (127认同)
使用"!="作为xor有问题.你可能会想到布尔(一)!=布尔(B)!=布尔(C)是一样的布尔(一)^布尔(B)^布尔(C).演员也要布尔,但我会推荐^.要知道第一个例子中出现了什么,请查看"操作员链接". (98认同)
也许"很明显,这是一个XOR?" 这是错误的问题.我们只是想看看两个问题的答案是否相同,并且认为我们使用XOR来实现它.例如,如果我们想确保我们不将苹果与橙子进行比较,那么"if xor(isApple(x),isApple(y))"是否真的比"if isApple(x)!= isApple(y)"更清晰?不是我! (44认同)
@elmo:+1用于指出差异,+1用于教我操作员链接是什么!我在营地里说!=不像^那样可读. (17认同)
应该是`bool(a)不是bool(b)`而是? (12认同)
正如@elmo所指出的,这不仅使代码难以理解,还不等同于xor操作,并且可能导致难以发现代码中的错误。[operator.xor](http://docs.python.org/library/operator.html#operator.xor)是更好的选择。 (2认同)
Zach Hirsch.. 448
您始终可以使用xor的定义从其他逻辑操作计算它:
(a and not b) or (not a and b)
但这对我来说有点过于冗长,乍一看并不是特别清楚.另一种方法是:
bool(a) ^ bool(b)
两个布尔值上的xor运算符是逻辑xor(与int不同,它是按位的).这是有道理的,因为bool
它只是一个子类int
,但实现只有值0
和1
.当域被限制为0
和时,逻辑xor等效于按位xor 1
.
所以logical_xor
函数将实现如下:
def logical_xor(str1, str2): return bool(str1) ^ bool(str2)
感谢尼克·科格伦了Python-3000的邮件列表上.
如果你已经将输入规范化为布尔值,那么!=是xor.
bool(a) != bool(b)
您始终可以使用xor的定义从其他逻辑操作计算它:
(a and not b) or (not a and b)
但这对我来说有点过于冗长,乍一看并不是特别清楚.另一种方法是:
bool(a) ^ bool(b)
两个布尔值上的xor运算符是逻辑xor(与int不同,它是按位的).这是有道理的,因为bool
它只是一个子类int
,但实现只有值0
和1
.当域被限制为0
和时,逻辑xor等效于按位xor 1
.
所以logical_xor
函数将实现如下:
def logical_xor(str1, str2): return bool(str1) ^ bool(str2)
感谢尼克·科格伦了Python-3000的邮件列表上.
在operator
模块中独占或已经内置到Python :
from operator import xor
xor(bool(a), bool(b)) # Note: converting to bools is essential
正如扎克解释的那样,你可以使用:
xor = bool(a) ^ bool(b)
就个人而言,我赞成略有不同的方言:
xor = bool(a) + bool(b) == 1
这种方言的灵感来自于我在学校学到的逻辑图表语言,其中"OR"由包含?1
(大于或等于1)的框表示,"XOR"由包含的框表示=1
.
这具有正确实现独占或多个操作数的优点.
"1 = a ^ b ^ c ..."表示真实操作数的数量是奇数.该运算符是"奇偶校验".
"1 = a + b + c ..."表示正好一个操作数为真.这是"排他性的",意思是"排除其他人之一".
Python的逻辑or
:A or B
:回报A
,如果bool(A)
是True
,否则返回B
Python的逻辑and
:A and B
:回报A
,如果bool(A)
是False
,否则返回B
为了保持大部分的思维方式,我的逻辑xor定义是:
def logical_xor(a, b): if bool(a) == bool(b): return False else: return a or b
这样,它可以返回a
,b
或False
:
>>> logical_xor('this', 'that') False >>> logical_xor('', '') False >>> logical_xor('this', '') 'this' >>> logical_xor('', 'that') 'that'
我已经测试了几种方法并且not a != (not b)
似乎是最快的.
这是一些测试
%timeit not a != (not b) 10000000 loops, best of 3: 78.5 ns per loop %timeit bool(a) != bool(b) 1000000 loops, best of 3: 343 ns per loop %timeit not a ^ (not b) 10000000 loops, best of 3: 131 ns per loop
奖励线程:
Anoder想法...只是你尝试(可能)pythonic表达«不是»以获得逻辑«xor»的行为
真相表将是:
>>> True is not True False >>> True is not False True >>> False is not True True >>> False is not False False >>>
对于您的示例字符串:
>>> "abc" is not "" True >>> 'abc' is not 'abc' False >>> 'abc' is not '' True >>> '' is not 'abc' True >>> '' is not '' False >>>
然而; 如上所述,它取决于你想要拉出任何几个字符串的实际行为,因为字符串不是boleans ......甚至更多:如果你"潜入Python",你会发现«The Peculiar nature of"和"和"或"» http://www.diveintopython.net/power_of_introspection/and_or.html
对不起,我写了英文,这不是我天生的语言.
问候.
独家或定义如下
def xor( a, b ): return (a or b) and not (a and b)
因为我没有看到xor的简单变体使用变量参数并且只对Truth值操作True或False,所以我只是把它扔到这里供任何人使用.正如其他人所指出的那样,非常(不是说非常)直截了当.
def xor(*vars): sum = False for v in vars: sum = sum ^ bool(v) return sum
用法也很简单:
if xor(False, False, True, False): print "Hello World!"
因为这是广义的n元逻辑XOR,所以只要True操作数的数量是奇数,它的真值就是True(并且不仅当正好一个是True时,这只是n-ary XOR为True的一种情况).
因此,如果您正在搜索只有其中一个操作数的只有True的n-ary谓词,您可能希望使用:
def isOne(*vars): sum = False for v in vars: if sum and v: return False else: sum = sum or v return sum
有时我发现自己使用1和0而不是布尔值True和False值.在这种情况下,xor可以定义为
z = (x + y) % 2
其中有以下真值表:
x |0|1| -+-+-+ 0|0|1| y -+-+-+ 1|1|0| -+-+-+
我知道这已经很晚了,但我有一个想法,它可能是值得的,只是为了文档.也许这会奏效:np.abs(x-y)
这个想法就是这样
如果x = True = 1且y = False = 0,则结果为| 1-0 | = 1 = True
如果x = False = 0且y = False = 0,则结果为| 0-0 | = 0 = False
如果x = True = 1且y = True = 1则结果为| 1-1 | = 0 = False
如果x = False = 0且y = True = 1,则结果为| 0-1 | = 1 = True
简单易懂:
sum( (bool(a), bool(b) ) == 1
如果你所追求的是独家选择,它可以扩展为多个参数:
sum( bool(x) for x in y ) % 2 == 1
这个怎么样?
(not b and a) or (not a and b)
将给a
如果b
是假
会给b
如果a
是假
会给False
否则
或者使用Python 2.5+三元表达式:
(False if a else b) if b else a
这里建议的一些实现将导致在某些情况下重复评估操作数,这可能导致意外的副作用,因此必须避免.
这就是说,一个xor
返回要么执行True
或False
相当简单; 如果可能的话,返回其中一个操作数的方法要复杂得多,因为对于哪个操作数应该是所选操作数没有共识,特别是当有两个以上的操作数时.例如,应该xor(None, -1, [], True)
返回None
,[]
还是False
?我敢打赌,每个答案对某些人来说都是最直观的答案.
对于True或False结果,有多达五种可能的选择:返回第一个操作数(如果它匹配值的最终结果,否则为boolean),返回第一个匹配(如果至少存在一个,则为boolean),返回最后一个操作数(if ... else ...),返回最后一个匹配(if ... else ...),或者总是返回boolean.总而言之,那是5**2 = 25种口味xor
.
def xor(*operands, falsechoice = -2, truechoice = -2): """A single-evaluation, multi-operand, full-choice xor implementation falsechoice, truechoice: 0 = always bool, +/-1 = first/last operand, +/-2 = first/last match""" if not operands: raise TypeError('at least one operand expected') choices = [falsechoice, truechoice] matches = {} result = False first = True value = choice = None # avoid using index or slice since operands may be an infinite iterator for operand in operands: # evaluate each operand once only so as to avoid unintended side effects value = bool(operand) # the actual xor operation result ^= value # choice for the current operand, which may or may not match end result choice = choices[value] # if choice is last match; # or last operand and the current operand, in case it is last, matches result; # or first operand and the current operand is indeed first; # or first match and there hasn't been a match so far if choice < -1 or (choice == -1 and value == result) or (choice == 1 and first) or (choice > 1 and value not in matches): # store the current operand matches[value] = operand # next operand will no longer be first first = False # if choice for result is last operand, but they mismatch if (choices[result] == -1) and (result != value): return result else: # return the stored matching operand, if existing, else result as bool return matches.get(result, result) testcases = [ (-1, None, True, {None: None}, [], 'a'), (None, -1, {None: None}, 'a', []), (None, -1, True, {None: None}, 'a', []), (-1, None, {None: None}, [], 'a')] choices = {-2: 'last match', -1: 'last operand', 0: 'always bool', 1: 'first operand', 2: 'first match'} for c in testcases: print(c) for f in sorted(choices.keys()): for t in sorted(choices.keys()): x = xor(*c, falsechoice = f, truechoice = t) print('f: %d (%s)\tt: %d (%s)\tx: %s' % (f, choices[f], t, choices[t], x)) print()
Python具有按位异或运算符,它是^
:
>>> True ^ False True >>> True ^ True False >>> False ^ True True >>> False ^ False False
您可以通过在应用xor(^
)之前将输入转换为布尔值来使用它:
bool(a) ^ bool(b)
(编辑-感谢Arel)
Many folks, including myself, need an xor
function that behaves like an n-input xor circuit, where n is variable. (See https://en.wikipedia.org/wiki/XOR_gate). The following simple function implements this.
def xor(*args): """ This function accepts an arbitrary number of input arguments, returning True if and only if bool() evaluates to True for an odd number of the input arguments. """ return bool(sum(map(bool,args)) % 2)
Sample I/O follows:
In [1]: xor(False, True) Out[1]: True In [2]: xor(True, True) Out[2]: False In [3]: xor(True, True, True) Out[3]: True