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

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

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

例如,我有两个期望是字符串的变量。我想测试其中只有一个包含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 "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for ^: 'str' and 'str'

How do you get the logical xor of two variables in Python?

For example, I have two variables that I expect to be strings. I want to test that only one of them contains a True value (is not None or the empty string):

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

The ^ operator seems to be bitwise, and not defined on all objects:

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

回答 0

如果您已经将输入归一化为布尔值,则!=为xor。

bool(a) != bool(b)

If you’re already normalizing the inputs to booleans, then != is xor.

bool(a) != bool(b)

回答 1

您始终可以使用xor的定义从其他逻辑运算中进行计算:

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

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

bool(a) ^ bool(b)

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

因此,该logical_xor功能将实现为:

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

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

You can always use the definition of xor to compute it from other logical operations:

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

But this is a little too verbose for me, and isn’t particularly clear at first glance. Another way to do it is:

bool(a) ^ bool(b)

The xor operator on two booleans is logical xor (unlike on ints, where it’s bitwise). Which makes sense, since bool is just a subclass of int, but is implemented to only have the values 0 and 1. And logical xor is equivalent to bitwise xor when the domain is restricted to 0 and 1.

So the logical_xor function would be implemented like:

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

Credit to Nick Coghlan on the Python-3000 mailing list.


回答 2

operator模块(与^运算符相同)中,Python内置了按位异或运算符:

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

Bitwise exclusive-or is already built-in to Python, in the operator module (which is identical to the ^ operator):

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

回答 3

正如Zach解释的那样,您可以使用:

xor = bool(a) ^ bool(b)

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

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

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

这具有正确实现互斥或在多个操作数上的优势。

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

As Zach explained, you can use:

xor = bool(a) ^ bool(b)

Personally, I favor a slightly different dialect:

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

This dialect is inspired from a logical diagramming language I learned in school where “OR” was denoted by a box containing ≥1 (greater than or equal to 1) and “XOR” was denoted by a box containing =1.

This has the advantage of correctly implementing exclusive or on multiple operands.

  • “1 = a ^ b ^ c…” means the number of true operands is odd. This operator is “parity”.
  • “1 = a + b + c…” means exactly one operand is true. This is “exclusive or”, meaning “one to the exclusion of the others”.

回答 4

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

为了保持大多数思维方式,我的逻辑异或定义为:

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

这样,它可以返回abFalse

>>> logical_xor('this', 'that')
False
>>> logical_xor('', '')
False
>>> logical_xor('this', '')
'this'
>>> logical_xor('', 'that')
'that'
  • Python logical or: A or B: returns A if bool(A) is True, otherwise returns B
  • Python logical and: A and B: returns A if bool(A) is False, otherwise returns B

To keep most of that way of thinking, my logical xor definintion would be:

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

That way it can return a, b, or False:

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

回答 5

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

I’ve tested several approaches and not a != (not b) appeared to be the fastest.

Here are some tests

%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

Edit: Examples 1 and 3 above are missing parenthes so result is incorrect. New results + truth() function as ShadowRanger suggested.

%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

回答 6

奖励线程:

提议者的想法…尝试(可能是)python表达式“不是”以便获得逻辑“异或”的行为

真值表将是:

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

然而; 正如上面所指出的,这取决于您想对任何几个字符串进行抽出的实际行为,因为字符串不是布尔值……甚至更多:如果您“深入Python”,您会发现“和”和“或”» http://www.diveintopython.net/power_of_introspection/and_or.html

对不起,我写的英语不是我的母语。

问候。

Rewarding thread:

Anoder idea… Just you try the (may be) pythonic expression «is not» in order to get behavior of logical «xor»

The truth table would be:

>>> True is not True
False
>>> True is not False
True
>>> False is not True
True
>>> False is not False
False
>>>

And for your example string:

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

However; as they indicated above, it depends of the actual behavior you want to pull out about any couple strings, because strings aren’t boleans… and even more: if you «Dive Into Python» you will find «The Peculiar Nature of “and” and “or”» http://www.diveintopython.net/power_of_introspection/and_or.html

Sorry my writed English, it’s not my born language.

Regards.


回答 7

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

>>> True ^ False
True
>>> True ^ True
False
>>> False ^ True
True
>>> False ^ False
False

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

bool(a) ^ bool(b)

(编辑-感谢Arel)

Python has a bitwise exclusive-OR operator, it’s ^:

>>> True ^ False
True
>>> True ^ True
False
>>> False ^ True
True
>>> False ^ False
False

You can use it by converting the inputs to booleans before applying xor (^):

bool(a) ^ bool(b)

(Edited – thanks Arel)


回答 8

因为我看不到使用变量参数的xor的简单变体,而仅对True值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元XOR为True的一种情况)。

因此,如果您要搜索仅在其中一个操作数正好存在时才为True的n元谓词,则可能需要使用:

def isOne(*vars):
    sum = False
    for v in vars:
        if sum and v:
            return False
        else:
            sum = sum or v
    return sum

As I don’t see the simple variant of xor using variable arguments and only operation on Truth values True or False, I’ll just throw it here for anyone to use. It’s as noted by others, pretty (not to say very) straightforward.

def xor(*vars):
    sum = False
    for v in vars:
        sum = sum ^ bool(v)
    return sum

And usage is straightforward as well:

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

As this is the generalized n-ary logical XOR, it’s truth value will be True whenever the number of True operands is odd (and not only when exactly one is True, this is just one case in which n-ary XOR is True).

Thus if you are in search of a n-ary predicate that is only True when exactly one of it’s operands is, you might want to use:

def isOne(*vars):
    sum = False
    for v in vars:
        if sum and v:
            return False
        else:
            sum = sum or v
    return sum

回答 9

异或定义如下

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

Exclusive Or is defined as follows

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

回答 10

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

z = (x + y) % 2

它具有以下真值表:

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

Sometimes I find myself working with 1 and 0 instead of boolean True and False values. In this case xor can be defined as

z = (x + y) % 2

which has the following truth table:

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

回答 11

我知道这很晚了,但是我有一个想法,可能只是为了文档而已。也许这会起作用: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

I know this is late, but I had a thought and it might be worth, just for documentation. Perhaps this would work:np.abs(x-y) The idea is that

  1. if x=True=1 and y=False=0 then the result would be |1-0|=1=True
  2. if x=False=0 and y=False=0 then the result would be |0-0|=0=False
  3. if x=True=1 and y=True=1 then the result would be |1-1|=0=False
  4. if x=False=0 and y=True=1 then the result would be |0-1|=1=True

回答 12

简单易懂:

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

如果您想要的是排他性选择,则可以将其扩展为多个参数:

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

Simple, easy to understand:

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

If an exclusive choice is what you’re after, it can be expanded to multiple arguments:

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

回答 13

这个怎么样?

(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

How about this?

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

will give a if b is false
will give b if a is false
will give False otherwise

Or with the Python 2.5+ ternary expression:

(False if a else b) if b else a

回答 14

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

这就是说,一个xor实现,无论是收益True还是False相当简单; 如果可能的话,返回一个操作数之一的技巧非常棘手,因为对于选择哪个操作数没有共识,尤其是当有两个以上的操作数时。例如,应该xor(None, -1, [], True)返回None[]还是False?我敢打赌,对于某些人来说,每个答案都是最直观的答案。

对于True或False结果,有多达五个可能的选择:返回第一个操作数(如果它与值中的最终结果匹配,否则为布尔值),返回第一个匹配项(如果至少存在一个,否则为布尔值),返回最后一个操作数(如果… else …),返回最后一个匹配项(如果… else …),或始终返回布尔值。总共有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()

Some of the implementations suggested here will cause repeated evaluation of the operands in some cases, which may lead to unintended side effects and therefore must be avoided.

That said, a xor implementation that returns either True or False is fairly simple; one that returns one of the operands, if possible, is much trickier, because no consensus exists as to which operand should be the chosen one, especially when there are more than two operands. For instance, should xor(None, -1, [], True) return None, [] or False? I bet each answer appears to some people as the most intuitive one.

For either the True- or the False-result, there are as many as five possible choices: return first operand (if it matches end result in value, else boolean), return first match (if at least one exists, else boolean), return last operand (if … else …), return last match (if … else …), or always return boolean. Altogether, that’s 5 ** 2 = 25 flavors of 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()

回答 15

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

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)

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

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

回答 16

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

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

例如,

bool(a) ^ bool(b)

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

请注意,可接受的答案是错误的: !=由于运算符链接的微妙之处,它与Python中的xor不同

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

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

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

To get the logical xor of two or more variables in Python:

  1. Convert inputs to booleans
  2. Use the bitwise xor operator (^ or operator.xor)

For example,

bool(a) ^ bool(b)

When you convert the inputs to booleans, bitwise xor becomes logical xor.

Note that the accepted answer is wrong: != is not the same as xor in Python because of the subtlety of operator chaining.

For instance, the xor of the three values below is wrong when using !=:

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

(P.S. I tried editing the accepted answer to include this warning, but my change was rejected.)


回答 17

当您知道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))

It’s easy when you know what XOR does:

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

回答 18

这将对两个(或多个)变量进行逻辑异或

str1 = raw_input("Enter string one:")
str2 = raw_input("Enter string two:")

any([str1, str2]) and not all([str1, str2])

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

此设置的第二个问题是,无论变量数量如何,它都会检查排他性。乍一看,这可能是一个功能,但是随着变量数量的增加(如果有的话),第一个问题变得更加重要。

This gets the logical exclusive XOR for two (or more) variables

str1 = raw_input("Enter string one:")
str2 = raw_input("Enter string two:")

any([str1, str2]) and not all([str1, str2])

The first problem with this setup is that it most likely traverses the whole list twice and, at a minimum, will check at least one of the elements twice. So it may increase code comprehension, but it doesn’t lend to speed (which may differ negligibly depending on your use case).

The second problem with this setup is that it checks for exclusivity regardless of the number of variables. This is may at first be regarded as a feature, but the first problem becomes a lot more significant as the number of variables increases (if they ever do).


回答 19

Xor ^在Python中。它返回:

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

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

Xor is ^ in Python. It returns :

  • A bitwise xor for ints
  • Logical xor for bools
  • An exclusive union for sets
  • User-defined results for classes that implements __xor__.
  • TypeError for undefined types, such as strings or dictionaries.

If you intend to use them on strings anyway, casting them in bool makes your operation unambiguous (you could also mean set(str1) ^ set(str2)).


回答 20

XOR是在中实现的operator.xor

XOR is implemented in operator.xor.


回答 21

这就是我编写任何真值表的方式。特别是对于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)

This is how I would code up any truth table. For xor in particular we have:

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

Just look at the T values in the answer column and string together all true cases with logical or. So, this truth table may be produced in case 2 or 3. Hence,

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

回答 22

我们可以通过使用以下命令轻松找到两个变量的异或:

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

例:

xor(真,假)>>>真

We can easily find xor of two variables by the using:

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

Example:

xor(True,False) >>> True