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

问题描述 投票:549回答:21

你如何在Python中获得两个变量的logical 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 "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for ^: 'str' and 'str'
python logical-operators
21个回答
1051
投票

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

bool(a) != bool(b)

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

7
投票

简单易懂:

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

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

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

6
投票

这个怎么样?

(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

6
投票

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

也就是说,返回xorTrueFalse实现相当简单;如果可能的话,返回其中一个操作数的方法要复杂得多,因为对于哪个操作数应该是所选操作数没有共识,特别是当有两个以上的操作数时。例如,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()

6
投票

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

z = (x + y) % 2

其中有以下真值表:

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

4
投票

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

4
投票

XOR在operator.xor中实现。


4
投票

这将获得两个(或更多)变量的逻辑异或

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

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

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

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


3
投票

Xor是Python中的^。它返回:

  • 整数的按位xor
  • 逻辑xor为bools
  • 集合的独家联盟
  • 用于实现__xor__的类的用户定义结果。
  • TypeError表示未定义的类型,例如字符串或字典。

如果你打算在字符串上使用它们,在bool中投射它们会使你的操作明确(你也可以指set(str1) ^ set(str2))。


3
投票

许多人,包括我自己,需要一个xor函数,其行为类似于n输入xor电路,其中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

431
投票

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

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

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

bool(a) ^ bool(b)

两个布尔值上的xor运算符是逻辑xor(与int不同,它是按位的)。这是有道理的,因为bool is just a subclass of int,但实现只有值01。当域限制为01时,逻辑xor等效于按位xor。

所以logical_xor函数将实现如下:

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

感谢Nick Coghlan on the Python-3000 mailing list


1
投票

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

因此,没有必要在任何库中或自己发明轮子。

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

-4
投票

我们可以通过使用很容易地找到两个变量的xor:

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

例:

xor(True,False)>>>是的


165
投票

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

from operator import xor
xor(bool(a), bool(b))

35
投票

正如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 ...”表示正好一个操作数为真。这是“排他性的”,意思是“排除其他人之一”。

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

为了保持大部分的思维方式,我的逻辑xor定义是:

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'

18
投票

我测试了几种方法,not a != (not b)似乎是最快的。

这是一些测试

%timeit not a != (not b)
10000000 loops, best of 3: 78.5 ns per loop

In [130]: %timeit bool(a) != bool(b)
1000000 loops, best of 3: 343 ns per loop

In [131]: %timeit not a ^ (not b)
10000000 loops, best of 3: 131 ns per loop

8
投票

奖励线程:

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

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

问候。


7
投票

独家或定义如下

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

7
投票

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

def xor(*vars):
    sum = bool(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 = bool(False)
    for v in vars:
        if sum and v:
            return False
        else:
            sum = sum or v
    return sum
© www.soinside.com 2019 - 2024. All rights reserved.