如何在Python中获取两个变量的逻辑异或?

如何在Python中获得两个变量的逻辑异或

例如,我希望有两个变量是字符串。我想测试其中只有一个包含True值(不是无或空字符串):

str1 = raw_input("Enter string one:")str2 = raw_input("Enter string two:")if logical_xor(str1, str2):print "ok"else:print "bad"

^运算符似乎是按位的,并没有在所有对象上定义:

>>> 1 ^ 10>>> 2 ^ 13>>> "abc" ^ ""Traceback (most recent call last):File "<stdin>", line 1, in <module>TypeError: unsupported operand type(s) for ^: 'str' and 'str'
1125279 次浏览

您始终可以使用xor的定义从其他逻辑操作计算它:

(a and not b) or (not a and b)

但这对我来说有点太冗长了,乍一看并不是特别清楚。另一种方法是:

bool(a) ^ bool(b)

两个布尔值上的xor运算符是逻辑xor(与int不同,它是按位的)。这是有道理的,从#0只是#1的子类开始,但实现为只有值01。当域限制为01时,逻辑xor等价于按位xor。

所以logical_xor函数将像这样实现:

def logical_xor(str1, str2):return bool(str1) ^ bool(str2)

信用Nick Coghlan在Python-3000邮件列表中

  • Python逻辑orA or B:如果bool(A)True,则返回A,否则返回B
  • Python逻辑andA and B:如果bool(A)False,则返回A,否则返回B

为了保持这种思维方式,我的逻辑异或定义是:

def logical_xor(a, b):if bool(a) == bool(b):return Falseelse:return a or b

这样它就可以返回abFalse

>>> logical_xor('this', 'that')False>>> logical_xor('', '')False>>> logical_xor('this', '')'this'>>> logical_xor('', 'that')'that'

独家或定义如下

def xor( a, b ):return (a or b) and not (a and b)

正如扎克所解释的,您可以使用:

xor = bool(a) ^ bool(b)

就个人而言,我喜欢稍微不同的方言:

xor = bool(a) + bool(b) == 1

这种方言的灵感来自于我在学校学到的逻辑图表语言,其中“OR”由包含≥1(大于或等于1)的框表示,“XOR”由包含=1的框表示。

这具有在多个操作数上正确实现异或的优点。

  • “1=a^b^c…”表示真操作数的数量是奇数。这个运算符是“奇偶校验”。
  • “1=a+b+c…”表示只有一个操作数为真。这是“异或”,意思是“一个操作数排除其他操作数”。

这个怎么样?

(not b and a) or (not a and b)

如果b为假,将给出a
如果a为false,将给出b
False,否则

或者使用Python 2.5+三元表达式:

(False if a else b) if b else a

如果您已经将输入规范化为布尔值,那么!=is xor。

bool(a) != bool(b)

这里建议的一些实现在某些情况下会导致操作数的重复计算,这可能会导致意想不到的副作用,因此必须避免。

也就是说,返回TrueFalsexor实现相当简单;如果可能,返回其中一个操作数的实现要棘手得多,因为对于哪个操作数应该是被选择的操作数没有共识,尤其是当有两个以上操作数时。例如,xor(None, -1, [], True)应该返回None[]还是False?我敢打赌,每个答案在一些人看来都是最直观的。

对于Tru-或False结果,有多达五个可能的选择:返回第一个操作数(如果它与值中的最终结果匹配,否则布尔值)、返回第一个匹配(如果至少存在一个,否则布尔值)、返回最后一个操作数(如果…否则…)、返回最后一个匹配(如果…否则…)或始终返回布尔值。总共,这是5**2=25种xor的味道。

def xor(*operands, falsechoice = -2, truechoice = -2):"""A single-evaluation, multi-operand, full-choice xor implementationfalsechoice, 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 = Falsefirst = Truevalue = choice = None# avoid using index or slice since operands may be an infinite iteratorfor operand in operands:# evaluate each operand once only so as to avoid unintended side effectsvalue = bool(operand)# the actual xor operationresult ^= value# choice for the current operand, which may or may not match end resultchoice = 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 farif choice < -1 or (choice == -1 and value == result) or (choice == 1 and first) or (choice > 1 and value not in matches):# store the current operandmatches[value] = operand# next operand will no longer be firstfirst = False# if choice for result is last operand, but they mismatchif (choices[result] == -1) and (result != value):return resultelse:# return the stored matching operand, if existing, else result as boolreturn 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()

由于我没有看到使用变量参数的xor的简单变体,并且只对True值True或False进行操作,我将把它扔到这里供任何人使用。这是由其他人指出,漂亮(不是说很)简单。

def xor(*vars):result = Falsefor v in vars:result = result ^ bool(v)return result

用法也很简单:

if xor(False, False, True, False):print "Hello World!"

由于这是广义的n元逻辑异或,因此当True操作数的数量为奇数时,它的真值将为True(不仅当正好有一个为True时,这只是n元异或为True的一种情况)。

因此,如果您正在搜索仅当其操作数之一为True时才为True的n元谓词,您可能希望使用:

def isOne(*vars):result = Falsefor v in vars:if result and v:return Falseelse:result = result or vreturn result

当你知道XOR做什么时很容易:

def logical_xor(a, b):return (a and not b) or (not a and b)
test_data = [[False, False],[False, True],[True, False],[True, True],]
for a, b in test_data:print '%r xor %s = %r' % (a, b, logical_xor(a, b))

XOR在operator.xor中实现。

按位异或已经内置在Python的operator模块中(与^运算符相同):

from operator import xorxor(bool(a), bool(b))  # Note: converting to bools is essential

有时我发现自己使用1和0而不是布尔值True和False。在这种情况下,xor可以定义为

z = (x + y) % 2

其中有以下真值表:

     x|0|1|-+-+-+0|0|1|y -+-+-+1|1|0|-+-+-+

这获取两个(或多个)变量的逻辑异或

str1 = raw_input("Enter string one:")str2 = raw_input("Enter string two:")
any([str1, str2]) and not all([str1, str2])

这种设置的第一个问题是它很可能会遍历整个列表两次,并且至少会检查至少一个元素两次。因此,它可能会提高代码理解能力,但它不会提高速度(根据您的用例,速度可能会有微不足道的差异)。

这种设置的第二个问题是,无论变量的数量如何,它都会检查排他性。这最初可能被视为一个特征,但随着变量数量的增加(如果有的话),第一个问题变得更加重要。

我已经测试了几种方法,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

编辑:上面的示例1和3缺少括号,因此结果不正确。新结果+truth()的功能与ShadowRanger建议的相同。

%timeit  (not a) ^  (not b)   # 47 ns%timeit  (not a) != (not b)   # 44.7 ns%timeit truth(a) != truth(b)  # 116 ns%timeit  bool(a) != bool(b)   # 190 ns

奖励线程:

另一个想法……只是你尝试(可能是)pythonic表达式“is not”以获得逻辑“xor”的行为

真值表将是:

>>> True is not TrueFalse>>> True is not FalseTrue>>> False is not TrueTrue>>> False is not FalseFalse>>>

对于您的示例字符串:

>>> "abc" is not  ""True>>> 'abc' is not 'abc'False>>> 'abc' is not ''True>>> '' is not 'abc'True>>> '' is not ''False>>>

然而,正如他们上面所指出的,这取决于你想要拉出任何一对字符串的实际行为,因为字符串不是boleans…甚至更多:如果你“潜入Python”,你会发现“和”和“或”的独特性质”http://www.diveintopython.net/power_of_introspection/and_or.html

对不起,我写的英语,这不是我出生的语言。

问候。

我知道这是晚了,但我有一个想法,它可能是值得的,只是为了留档。也许这将工作:np.abs(x-y)这个想法是

  1. 如果x=True=1,y=False=0,则结果为|1-0|=1=True
  2. 如果x=False=0,y=False=0,则结果为|0-0|=0=False
  3. 如果x=True=1且y=True=1,则结果为|1-1|=0=False
  4. 如果x=False=0和y=True=1,那么结果将是|0-1|=1=True

简单,容易理解:

sum(bool(a), bool(b)) == 1

如果一个排他性选择是你想要的,即从n中选择1选择,它可以扩展为多个参数:

sum(bool(x) for x in y) == 1

我们可以很容易地找到两个变量的异或:

def xor(a,b):return a !=b

示例:

XOR(True, False)>>>True

Xor在Python中是^。它返回:

  • 整数的按位异或
  • 布尔的逻辑异或
  • 集合的排他并集
  • 实现__xor__的类的用户定义结果。
  • 未定义类型的TypeError,例如字符串或字典。

如果您打算在字符串上使用它们,将它们转换为bool会使您的操作明确无误(您也可以表示set(str1) ^ set(str2))。

许多人,包括我自己,需要一个xor函数,其行为类似于n输入异或电路,其中n是可变的。(参见https://en.wikipedia.org/wiki/XOR_gate)。以下简单函数实现了这一点。

def xor(*args):"""This function accepts an arbitrary number of input arguments, returning Trueif and only if bool() evaluates to True for an odd number of the input arguments."""
return bool(sum(map(bool,args)) % 2)

示例I/O如下:

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

Python有一个按位异或运算符,它是^

>>> True ^ FalseTrue>>> True ^ TrueFalse>>> False ^ TrueTrue>>> False ^ FalseFalse

您可以通过在应用xor(^)之前将输入转换为布尔值来使用它:

bool(a) ^ bool(b)

(编辑-感谢艾瑞尔)

在Python中获取两个或多个变量的逻辑异或:

  1. 将输入转换为布尔值
  2. 使用按位异或运算符(^operator.xor

例如,

bool(a) ^ bool(b)

当您将输入转换为布尔值时,按位 xor变为逻辑 xor。

注意,接受的答案是错误的:!=与Python中的xor不同,因为算子链的微妙之处。

例如,当使用!=时,下面三个值的xor是错误的:

True ^  False ^  False  # True, as expected of XORTrue != False != False  # False! Equivalent to `(True != False) and (False != False)`

(附:我尝试编辑已接受的答案以包含此警告,但我的更改被拒绝。

这就是我编写任何真值表的方式。特别是对于xor,我们有:

| a | b  | xor   |             ||---|----|-------|-------------|| T | T  | F     |             || T | F  | T     | a and not b || F | T  | T     | not a and b || F | F  | F     |             |

只需查看答案列中的T值并将所有真实情况与逻辑或串在一起。因此,此真值表可能在情况2或3中产生。因此,

xor = lambda a, b: (a and not b) or (not a and b)

Python处理逻辑操作的方式可能会令人困惑,所以我的实现为用户提供了一个简单的True/False答案的选项(默认情况下)。实际的Python结果可以通过将可选的第三个参数设置为无来获得。

def xor(a, b, true=True, false=False): # set true to None to get actual Python resultab1 = a and not bab2 = not a and bif bool(ab1) != bool(ab2):return (ab1 or ab2) if true is None else trueelse:return false

假设A和B是布尔值。

A is not B

您使用与C中相同的XOR运算符,即^

我不知道为什么,但投票最多的解决方案建议bool(A) != bool(B),而我想说-符合C^的运算符,最明显的解决方案是:

bool(A) ^ bool(B)

对于任何来自C或任何C派生语言的人来说,这更具可读性和可理解性…

在打代码高尔夫时,可能

not A ^ (not B)

将是胜利者。not作为布尔值的转换器(比bool()少一个字母。对于第一个表达式,在某些情况下,可以省略假说。嗯,这取决于,在必须做not(A) ^ (not(B))的情况下,bool()需要相同数量的字母…

只是因为我没有在其他地方看到它,这也起到了作用:

def logical_xor(a, b):return not b if a else bool(b)

我不确定它是否比公认的解决方案bool(a)“更好”/更具可读性/更Pythonic!=bool(b)。

这是一个概括。

def xor(*orands):return sum(bool(x) for x in orands) == 1

你可以测试一下

# testfrom itertools import productfor a, b, c in product((False, True), repeat=3):print(f'{int(a)}{int(b)}{int(c)}|{xor(a,b,c)}')

输出:

000|False
001|True
010|True
011|False
100|True
101|False
110|False
111|假