你如何在Python中获得两个变量的逻辑xor?

Zac*_*sch 597 python logical-operators

你如何在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"
Run Code Online (Sandbox Code Playgroud)

^运营商似乎是按位,并在所有对象没有定义:

>>> 1 ^ 1
0
>>> 2 ^ 1
3
>>> "abc" ^ ""
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for ^: 'str' and 'str'
Run Code Online (Sandbox Code Playgroud)

A. *_*ady 1113

如果你已经将输入规范化为布尔值,那么!=是xor.

bool(a) != bool(b)
Run Code Online (Sandbox Code Playgroud)

  • 虽然这很聪明而且简短,但我不相信它很干净.当有人在代码中读取此构造时,对于他们来说,这是一个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认同)
  • @Arel:对于“bool”,对于单个比较,“!=”与异或完全相同。它仅适用于行为不同的连锁情况。不值得投反对票。 (7认同)
  • 只是给像我这样天真无邪的小贴士:小心操作符的优先级!我想检查两个变量是否都为空或都为非空,并最终编写了`(a is None != b is None)`。嗯,这是错误的! (2认同)
  • @Jason 您使用的是 `==` 而不是 `!=`。如有必要,您可以通过蛮力验证:`for b1, b2 in ((True, False), (True, True), (False, False): assert (b1 != b2) == (b1 ^ b1)`。这是真值表验证(注意运算符的可交换性)。我将其作为练习使用推理规则进行验证;) (2认同)
  • 正如@elmo所指出的,这不仅使代码难以理解,还不等同于xor操作,并且可能导致难以发现代码中的错误。[operator.xor](http://docs.python.org/library/operator.html#operator.xor)是更好的选择。 (2认同)
  • @wjandrea `True is True` [由 Python 语言参考保证](https://docs.python.org/3/reference/datamodel.html#the-standard-type-hierarchy)。[感谢佩德罗询问](/sf/ask/1738999671/) (2认同)

Zac*_*sch 448

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

(a and not b) or (not a and b)
Run Code Online (Sandbox Code Playgroud)

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

bool(a) ^ bool(b)
Run Code Online (Sandbox Code Playgroud)

两个布尔值上的xor运算符是逻辑xor(与int不同,它是按位的).这是有道理的,因为bool它只是一个子类int,但实现只有值01.当域被限制为0和时,逻辑xor等效于按位xor 1.

所以logical_xor函数将实现如下:

def logical_xor(str1, str2):
    return bool(str1) ^ bool(str2)
Run Code Online (Sandbox Code Playgroud)

感谢尼克·科格伦了Python-3000的邮件列表上.

  • 你应该把nots放在第一个像`(不是b和a)或(不是a和b)`这样它返回字符串,如果有的话,这似乎是函数操作的pythonic方式. (10认同)
  • 很棒的帖子,但是为你的参数命名的所有方法,为什么'str1'和'str2'? (7认同)
  • @Zach Hirsch 为了可读性,您是否可以使用 (not a and b) 而不是 (b and not a) 或者定义是否与 xor 不一致。 (2认同)
  • @TokenMacGuy:你有什么建议他应该给他们命名? (2认同)

sin*_*boy 173

operator模块中独占或已经内置到Python :

from operator import xor
xor(bool(a), bool(b))  # Note: converting to bools is essential
Run Code Online (Sandbox Code Playgroud)

  • 小心,这也是按位:`xor(1,2)`返回`3`.来自docstring:`xor(a,b) - 与^ b相同.请记住,从`operator`导入的任何内容都只是现有内置中缀运算符的函数形式. (70认同)
  • 这个xor是按位的,使用它与^运算符具有相同的效果. (6认同)
  • @askewchan:`bool`类型重载`__xor__`返回布尔值.它会工作得很好,但是当bool(a)^ bool(b)`执行完全相同的事情时它会有些过分. (5认同)
  • @Quantum7:是的,我不知道你为什么这么告诉我.我只是说`bool`类型实现了`__xor__`方法*,特别是因为`^`调用它*.关键是`bool(a)^ bool(b)`工作正常,这里不需要使用`operator.xor()`函数. (4认同)
  • 这就是我需要的.反向工程恶意软件时,很多时候字符串会被破坏,直到进行异或操作.使用此chr(xor(ord("n"),0x1A))='t' (2认同)

dda*_*daa 39

正如扎克解释的那样,你可以使用:

xor = bool(a) ^ bool(b)
Run Code Online (Sandbox Code Playgroud)

就个人而言,我赞成略有不同的方言:

xor = bool(a) + bool(b) == 1
Run Code Online (Sandbox Code Playgroud)

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

这具有正确实现独占或多个操作数的优点.

  • "1 = a ^ b ^ c ..."表示真实操作数的数量是奇数.该运算符是"奇偶校验".
  • "1 = a + b + c ..."表示正好一个操作数为真.这是"排他性的",意思是"排除其他人之一".

  • 所以,True + True + False + True == 3,而3!= 1,但是True XOR True XOR False XOR True == True.你能详细说明"在多个操作数上正确实现XOR"吗? (12认同)
  • 此外,三向XOR与两个XOR的操作顺序组合之间存在差异.因此,3-WAY-XOR(A,B,C)与XOR(XOR(A,B),C)*不相同.而ddaa的例子是前者,而你的则是后者. (5认同)
  • @tzot你的例子失败了,因为根据ddaa的解决方案,你一次只对两个变量应用加法.所以,正确的方式来写这一切必须是`(((((真+真)== 1)+假)== 1)+真)== 1`.这里给出的答案完全概括为多个操作数. (3认同)
  • @ Mr.F你的解释并没有真正原谅这个答案.在Python中,如果你只做'True + True + False + True`,你*做*得到'3`,而'True + True + False + True == 3`给出'True`而True + True + False + True == 1`返回'False`.换句话说,这里的答案没有正确概括; 要做到这一点,你需要做额外的工作.同时,一个简单的"True ^ True ^ False ^ True"按预期工作. (3认同)
  • @EMS:谢谢。你的反对意见(对我来说)澄清了 ddaa 的含义。 (2认同)
  • @ jpmc26我不明白你的评论.添加方法旨在概括您要检查*正好一个*操作数为"True"的操作,即多个异常XOR.这是一种不同的操作,例如,`A XOR B XOR ... XOR Z`.换句话说,如果您计划使用基于加法的版本,那么在提交操作数为"True + True + False + True"时,您应该期望结果为"False",因为其中多个是"True". ,如果条件检查"== 1",则有效. (2认同)
  • 因此,当您编写 `True + True + False + True == 1` 时,如果您使用加法方法,则会返回正确且需要的 `False`。也许我误解了你的意思,但我不明白有什么问题。一个人是否想要一个或另一个操作取决于他们,对于多元异或,这只是一个语义问题,即这些“是异或”中的哪一个。 (2认同)

nos*_*klo 24

  • 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
Run Code Online (Sandbox Code Playgroud)

这样,它可以返回a,bFalse:

>>> logical_xor('this', 'that')
False
>>> logical_xor('', '')
False
>>> logical_xor('this', '')
'this'
>>> logical_xor('', 'that')
'that'
Run Code Online (Sandbox Code Playgroud)

  • @Denis Barmenkov:请注意,python逻辑运算符`和`以及`或`不会返回逻辑值.''foo'和'bar'`返回`'bar'` ... (9认同)
  • 这对我来说似乎很糟糕,或者至少很奇怪.其他内置逻辑运算符都不返回三个可能值中的一个. (5认同)
  • 乍一看,前面的2个答案看起来是最好的,但是第二个想法,这个答案实际上是唯一真正正确的答案,即它是唯一一个提供与所构建的一致的`xor`实现的例子.在`和`和`或`中.然而,当然,在实际情况中,`bool(a)^ bool(b)`或甚至`a ^ b`(如果`a`和`b`被称为`bool`)当然更简洁. (5认同)
  • @Zach Hirsch:这就是为什么我说“保持*大部分*的思维方式”的原因-因为当对或错时,都不会有好的结果 (2认同)

Rug*_*nar 21

我已经测试了几种方法并且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
Run Code Online (Sandbox Code Playgroud)

  • 这就是我生命中的 100 纳秒,我不会再回来了;-) (9认同)
  • 对于中间时间,您可以在模块顶部执行“fromoperatorimporttruth”,并测试“truth(a)!=truth(b)”。`bool` 作为构造函数在 C 级别有很多不可避免的开销(它必须接受相当于 `*args、**kwargs` 的参数,并解析 `tuple` 和 `dict` 来提取它们),其中 ` true(作为一个函数)可以使用不需要“tuple”或“dict”的优化路径,并且运行时间大约是基于“bool”的解决方案的一半(但仍然比基于“not”的解决方案长)解决方案)。 (6认同)

ala*_*ere 13

假设 A 和 B 是布尔值。

A is not B
Run Code Online (Sandbox Code Playgroud)


Gwa*_*Kim 9

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

我不知道为什么,但最受支持的解决方案建议bool(A) != bool(B),而我会说 - 与 C 的运算符一致^,最明显的解决方案是:

bool(A) ^ bool(B)
Run Code Online (Sandbox Code Playgroud)

对于来自任何语言C或任何C派生语言的任何人来说,这都更具可读性并且可以立即理解......

在进行代码高尔夫时,可能

not A ^ (not B)
Run Code Online (Sandbox Code Playgroud)

将成为赢家。使用notas 布尔值转换器(小于 1 个字母bool()。在某些情况下,对于第一个表达式,可以省略括号。好吧,这取决于,在必须这样做的情况下not(A) ^ (not(B))bool()需要相同数量的字母......


小智 8

奖励线程:

Anoder想法...只是你尝试(可能)pythonic表达«不是»以获得逻辑«xor»的行为

真相表将是:

>>> True is not True
False
>>> True is not False
True
>>> False is not True
True
>>> False is not False
False
>>>
Run Code Online (Sandbox Code Playgroud)

对于您的示例字符串:

>>> "abc" is not  ""
True
>>> 'abc' is not 'abc' 
False
>>> 'abc' is not '' 
True
>>> '' is not 'abc' 
True
>>> '' is not '' 
False
>>> 
Run Code Online (Sandbox Code Playgroud)

然而; 如上所述,它取决于你想要拉出任何几个字符串的实际行为,因为字符串不是boleans ......甚至更多:如果你"潜入Python",你会发现«The Peculiar nature of"和"和"或"» http://www.diveintopython.net/power_of_introspection/and_or.html

对不起,我写了英文,这不是我天生的语言.

问候.


Are*_*rel 8

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

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

例如,

bool(a) ^ bool(b)
Run Code Online (Sandbox Code Playgroud)

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

请注意,接受的答案是错误的: !=由于operator chaining的微妙之处,因此与 Python 中的 xor 不同。

例如,以下三个值的异或在使用时是错误的!=

True ^  False ^  False  # True, as expected of XOR
True != False != False  # False! Equivalent to `(True != False) and (False != False)`
Run Code Online (Sandbox Code Playgroud)

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


S.L*_*ott 7

独家或定义如下

def xor( a, b ):
    return (a or b) and not (a and b)
Run Code Online (Sandbox Code Playgroud)

  • Python`和`以及`或`做短路.任何`xor`实现都不能短路,所以已经存在差异; 因此,没有理由`xor`应该像`和`+`或`那样运作. (10认同)
  • 这将为xor('this','')返回True,并遵循python的方式,它应该返回'this'. (2认同)
  • 我的意思是为了与其他python逻辑运算符保持一致 - 当我这样做时,Python不返回True('this'或''),它返回'this'.但是在你的函数xor('this','')中返回True.它应该像"或"python内置函数那样返回'this'. (2认同)

小智 7

因为我没有看到xor的简单变体使用变量参数并且只对Truth值操作True或False,所以我只是把它扔到这里供任何人使用.正如其他人所指出的那样,非常(不是说非常)直截了当.

def xor(*vars):
    sum = False
    for v in vars:
        sum = sum ^ bool(v)
    return sum
Run Code Online (Sandbox Code Playgroud)

用法也很简单:

if xor(False, False, True, False):
    print "Hello World!"
Run Code Online (Sandbox Code Playgroud)

因为这是广义的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
Run Code Online (Sandbox Code Playgroud)


Ste*_*e L 7

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

z = (x + y) % 2
Run Code Online (Sandbox Code Playgroud)

其中有以下真值表:

     x
   |0|1|
  -+-+-+
  0|0|1|
y -+-+-+
  1|1|0|
  -+-+-+
Run Code Online (Sandbox Code Playgroud)


小智 7

我知道这已经很晚了,但我有一个想法,它可能是值得的,只是为了文档.也许这会奏效: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


c z*_*c z 7

简单易懂:

sum( (bool(a), bool(b) ) == 1
Run Code Online (Sandbox Code Playgroud)

如果你所追求的是独家选择,它可以扩展为多个参数:

sum( bool(x) for x in y ) % 2 == 1
Run Code Online (Sandbox Code Playgroud)

  • `sum(map(bool, y)) % 2 == 1` (2认同)

Mar*_*rot 6

这个怎么样?

(not b and a) or (not a and b)
Run Code Online (Sandbox Code Playgroud)

将给a如果b是假
会给b如果a是假
会给False否则

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

(False if a else b) if b else a
Run Code Online (Sandbox Code Playgroud)


小智 6

这里建议的一些实现将导致在某些情况下重复评估操作数,这可能导致意外的副作用,因此必须避免.

这就是说,一个xor返回要么执行TrueFalse相当简单; 如果可能的话,返回其中一个操作数的方法要复杂得多,因为对于哪个操作数应该是所选操作数没有共识,特别是当有两个以上的操作数时.例如,应该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()
Run Code Online (Sandbox Code Playgroud)


Tom*_*Gal 6

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

>>> True ^ False
True
>>> True ^ True
False
>>> False ^ True
True
>>> False ^ False
False
Run Code Online (Sandbox Code Playgroud)

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

bool(a) ^ bool(b)
Run Code Online (Sandbox Code Playgroud)

(编辑-感谢Arel)

  • @Arel 但事实并非如此。`a ^ b` 是多态性。如果“a”和“b”是“bool”实例,则结果也将为“bool”。这种行为很难被称为“按位”异或。 (2认同)

sna*_*aul 6

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

| a | b  | xor   |             |
|---|----|-------|-------------|
| T | T  | F     |             |
| T | F  | T     | a and not b |
| F | T  | T     | not a and b |
| F | F  | F     |             |
Run Code Online (Sandbox Code Playgroud)

只需查看答案栏中的 T 值,然后用逻辑“或”将所有正确的情况串起来。因此,这个真值表可以在情况 2 或 3 中产生。因此,

xor = lambda a, b: (a and not b) or (not a and b)
Run Code Online (Sandbox Code Playgroud)


Art*_*cek 5

Xor^在 Python 中。它返回:

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

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


Phi*_*man 5

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)
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)