如何获得Python中两个变量的逻辑XOR?

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

如何获得Python中两个变量的逻辑XOR?

例如,我有两个期望是字符串的变量。我想测试它们中只有一个包含真值(不是无或空字符串):

1
2
3
4
5
6
str1 = raw_input("Enter string one:")
str2 = raw_input("Enter string two:")
if logical_xor(str1, str2):
    print"ok"
else:
    print"bad"

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

1
2
3
4
5
6
7
8
>>> 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'


如果您已经在规范布尔值的输入,那么!=异或。

1
bool(a) != bool(b)


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

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

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

1
bool(a) ^ bool(b)

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

因此,logical_xor功能的实现方式如下:

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

归功于python-3000邮件列表中的nick coghlan。


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

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


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

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

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

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

这种方言是从我在学校学过的一种逻辑图表语言中得到启发的,其中"or"由一个包含≥1的盒子(大于或等于1)表示,"xor"由一个包含=1的盒子表示。

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

  • "1=a^b^c…"表示真正的操作数是奇数。这个运算符是"奇偶校验"。
  • "1=a+b+c…"表示只有一个操作数为真。这是"排他性的或",意思是"一方排除另一方"。


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

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

1
2
3
4
5
def logical_xor(a, b):
    if bool(a) == bool(b):
        return False
    else:
        return a or b

这样可以返回ABFalse

1
2
3
4
5
6
7
8
>>> logical_xor('this', 'that')
False
>>> logical_xor('', '')
False
>>> logical_xor('this', '')
'this'
>>> logical_xor('', 'that')
'that'


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

这是一些测试

1
2
3
4
5
6
7
8
%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


我知道这很晚了,但我有一个想法,这可能是值得的,只是为了记录。也许这会奏效:np.abs(x-y)的想法是

  • 如果x=真=1,y=假=0,则结果将为1-0=1=真
  • 如果x=false=0,y=false=0,则结果为0-0=0=false。
  • 如果x=真=1,y=真=1,则结果将为1-1=0=假
  • 如果x=false=0,y=true=1,则结果为0-1=1=true。

  • 奖励线:

    更重要的想法…只是你试试(可能是)Python的表情?不是吗?为了得到合乎逻辑的行为?异或?

    真相表应该是:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    >>> True is not True
    False
    >>> True is not False
    True
    >>> False is not True
    True
    >>> False is not False
    False
    >>>

    对于您的示例字符串:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    >>>"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

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

    当做。


    因为我没有看到XOR的简单变体使用变量参数,并且只对真值true或false进行操作,所以我将把它扔到这里供任何人使用。正如其他人所指出的,相当(不是说非常)直截了当。

    1
    2
    3
    4
    5
    def xor(*vars):
        sum = bool(False)
        for v in vars:
            sum = sum ^ bool(v)
        return sum

    使用也很简单:

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

    因为这是广义的n元逻辑异或,所以当真操作数的数目为奇数时,它的真值将为真(不仅当一个真操作数为真时,这只是n元异或为真的一种情况)。

    因此,如果您正在搜索一个n元谓词,而该谓词只有在其中一个操作数为时才为真,则可能需要使用:

    1
    2
    3
    4
    5
    6
    7
    8
    def isOne(*vars):
        sum = bool(False)
        for v in vars:
            if sum and v:
                return False
            else:
                sum = sum or v
        return sum


    排他或定义如下

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


    简单易懂:

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

    如果您所追求的是独占选择,则可以将其扩展为多个参数:

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

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

    1
    z = (x + y) % 2

    它有以下真值表:

    1
    2
    3
    4
    5
    6
    7
         x
       |0|1|
      -+-+-+
      0|0|1|
    y -+-+-+
      1|1|0|
      -+-+-+

    这个怎么样?

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

    如果B是假的,将给予A。如果A是假的,将给予B。否则将给予False

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

    1
    (False if a else b) if b else a

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

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

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    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()


    XOR在operator.xor中实现。


    当你知道XOR的作用时很容易:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    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))

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

    1
    2
    3
    4
    str1 = raw_input("Enter string one:")
    str2 = raw_input("Enter string two:")

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

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

    这个设置的第二个问题是,不管变量的数量如何,它都会检查排他性。这一点一开始可能被视为一个特性,但随着变量数量的增加(如果有),第一个问题变得更加重要。


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

    1
    2
    3
    4
    5
    6
    7
    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如下:

    1
    2
    3
    4
    5
    6
    7
    8
    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

    xor是python中的^。它返回:

    • 整数的位异或
    • 布尔值的逻辑异或
    • 集合的独占联合
    • 实现__xor__的类的用户定义结果。
    • 未定义类型(如字符串或字典)的类型错误。

    如果你想在字符串上使用它们,把它们放在bool中可以使你的操作明确(你也可以指set(str1) ^ set(str2))。


    我们可以通过以下方法很容易地找到两个变量的xor:

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

    例子:

    xor(True,False) >>> True

    < /块引用>< /块引用>