如何在 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'
a xor a
被定义为 (a and not b) or (not a and b)
,因此当 a
和 b
是字符串或任何其他类型时,a xor b
应该产生任何 (a and not b) or (not a and b)
产生.
如果您已经将输入标准化为布尔值,则 != 是异或。
bool(a) != bool(b)
您始终可以使用 xor 的定义从其他逻辑操作中计算它:
(a and not b) or (not a and b)
但这对我来说有点过于冗长,乍一看并不是特别清楚。另一种方法是:
bool(a) ^ bool(b)
两个布尔值上的异或运算符是逻辑异或(与整数不同,它是按位的)。这是有道理的,因为 bool
is just a subclass of int
,但实现为只有值 0
和 1
。当域被限制为 0
和 1
时,逻辑异或等效于按位异或。
所以 logical_xor
函数的实现方式如下:
def logical_xor(str1, str2):
return bool(str1) ^ bool(str2)
归功于 Nick Coghlan on the Python-3000 mailing list。
(not b and a) or (not a and b)
那样将 nots 放在第一位,这样如果有字符串,它就会返回字符串,这似乎是函数操作的 Pythonic 方式。
按位 异或已内置于 Python 的 operator
模块中(与 ^
运算符相同):
from operator import xor
xor(bool(a), bool(b)) # Note: converting to bools is essential
xor(1, 2)
返回 3
。来自文档字符串:xor(a, b) -- Same as a ^ b.
请记住,从 operator
导入的任何内容都只是现有内置中缀运算符的一种功能形式。
bool
类型重载 __xor__
以返回布尔值。它会工作得很好,但是当 bool(a) ^ bool(b)
做完全相同的事情时它就过分了。
^
运算符在内部调用 __xor__
。
bool
类型实现了 __xor__
方法特别是因为 ^
调用它。重点是 bool(a) ^ bool(b)
可以正常工作,这里不需要使用 operator.xor()
函数。
如 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...” 意味着只有一个操作数为真。这是“exclusive or”,意思是“一个排除其他”。
(((((True + True)==1)+False)==1)+True)==1
。这里给出的答案完全推广到多个操作数。
True + True + False + True
,您执行会得到 3
,并且 True + True + False + True == 3
会返回 True
,而 True + True + False + True == 1
会返回 False
。换句话说,这里的答案没有正确概括。为此,您需要做额外的工作。同时,一个简单的 True ^ True ^ False ^ True
按预期工作。
True
的操作,即多元 XOR。这是与例如 A XOR B XOR ... XOR Z
不同的操作。换句话说,如果您计划使用基于加法的版本,那么在 True + True + False + True
中提交操作数后,您应该期望结果为 False
,因为其中不止一个是 True
,如果条件满足检查 == 1
。
Python 逻辑或:A 或 B:如果 bool(A) 为 True,则返回 A,否则返回 B
Python 逻辑与:A 和 B:如果 bool(A) 为 False,则返回 A,否则返回 B
为了保持这种思维方式的大部分,我的逻辑异或定义是:
def logical_xor(a, b):
if bool(a) == bool(b):
return False
else:
return a or b
这样它就可以返回 a
、b
或 False
:
>>> logical_xor('this', 'that')
False
>>> logical_xor('', '')
False
>>> logical_xor('this', '')
'this'
>>> logical_xor('', 'that')
'that'
and
和 or
不会返回逻辑值。 'foo' and 'bar'
返回 'bar'
...
xor
实现示例的答案 -在 and
和 or
中。但是,当然,在实际情况下,bool(a) ^ bool(b)
甚至 a ^ b
(如果已知 a
和 b
为 bool
)当然更简洁。
我测试了几种方法,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 缺少括号,因此结果不正确。 ShadowRanger 建议的新结果 + truth()
函数。
%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
from operator import truth
,然后测试 truth(a) != truth(b)
。 bool
作为构造函数在 C 级别有很多不可避免的开销(它必须接受与 *args, **kwargs
等效的参数并解析 tuple
和 dict
以提取它们),其中 truth
(作为函数)可以使用不需要 tuple
或 dict
的优化路径,并且运行时间大约是基于 bool
的解决方案的一半(但仍比基于 not
的解决方案更长)。
Python 有一个按位异或运算符,它是 ^
:
>>> True ^ False
True
>>> True ^ True
False
>>> False ^ True
True
>>> False ^ False
False
您可以通过在应用 xor (^
) 之前将输入转换为布尔值来使用它:
bool(a) ^ bool(b)
(已编辑 - 感谢 Arel)
^
是 按位 xor(不是像所问问题那样的逻辑 xor)。 bool(2) ^ bool(3)
给出了与 bool(2 ^ 3)
不同的答案。
a ^ b
是多态。如果 a
和 b
是 bool
实例,则结果也将是 bool
。这种行为很难被称为“按位”异或。
^
定义为按位,尽管有趣的是为 bool
和 int
保留类型类型。注意:True ^ 2
是 3
,说明它确实是按位的。
bool ^ int
案例首先将所有内容都转换为 int
。尽管如此,Python 为 int
中的许多位和 bool
中表示的一位内置了 ^
运算符,因此两者都是 bitwise,但 bitwise< /i> xor for a single bit is logical xor for booleans。
xor
,来自工程背景,但对我来说,这本能地感觉像是一种数学力量,即 2^3 = pow(2,3)
,这意味着我总是明确地注释以防止混淆。
简单易懂:
sum(bool(a), bool(b)) == 1
如果您需要一个独占选项,即从 n
中选择 1
选项,则可以将其扩展为多个参数:
sum(bool(x) for x in y) == 1
sum(map(bool, y)) % 2 == 1
sum
的理由,bool(a) + bool(b) == 1
做同样的事情。
在 Python 中获取两个或多个变量的逻辑异或:
将输入转换为布尔值 使用按位异或运算符(^ 或 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 我尝试编辑接受的答案以包含此警告,但我的更改被拒绝。)
由于我没有看到使用变量参数的 xor 的简单变体,并且仅对真值 True 或 False 进行操作,因此我将把它扔在这里供任何人使用。正如其他人所指出的那样,非常(不是说非常)直截了当。
def xor(*vars):
result = False
for v in vars:
result = result ^ bool(v)
return result
用法也很简单:
if xor(False, False, True, False):
print "Hello World!"
由于这是广义的 n 元逻辑 XOR,因此只要 True 操作数的数量为奇数,其真值将为 True(不仅当恰好一个为 True 时,这只是 n 元 XOR 为 True 的一种情况)。
因此,如果您正在寻找一个 n 元谓词,该谓词仅在其操作数之一为真时才为真,您可能希望使用:
def isOne(*vars):
result = False
for v in vars:
if result and v:
return False
else:
result = result or v
return result
(bool(False) is False) == True
。您可以在这些行上使用 False
。
奖励线程:
阳极的想法......只是你尝试(可能是)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
>>>
然而;正如他们上面所指出的,这取决于你想要提取任何一对字符串的实际行为,因为字符串不是布尔值......甚至更多:如果你«潜入 Python»,您会发现 «The Peculiar Nature of "和”和“或”» http://www.diveintopython.net/power_of_introspection/and_or.html
对不起,我的书面英语,它不是我出生的语言。
问候。
我知道这已经晚了,但我有一个想法,这可能是值得的,只是为了记录。也许这会起作用:np.abs(x-y)
这个想法是
如果 x=True=1 和 y=False=0 则结果为 |1-0|=1=True 如果 x=False=0 且 y=False=0 则结果为 |0-0|=0 =False if x=True=1 and y=True=1 then the result will be |1-1|=0=False if x=False=0 and y=True=1 then the result will be |0-1| =1=真
abs
,python 将负数解释为真实,尽管这在 imo 中非常晦涩(if (x > 1) - (y > 3)
是什么意思?
鉴于 A 和 B 是布尔值。
A is not B
异或定义如下
def xor( a, b ):
return (a or b) and not (a and b)
and
和 or
会短路。任何 xor
实现都不能短路,因此已经存在差异;因此,没有理由让 xor
像 and
+or
那样运行。
这里建议的一些实现在某些情况下会导致对操作数的重复评估,这可能会导致意想不到的副作用,因此必须避免。
也就是说,返回 True
或 False
的 xor
实现相当简单;如果可能的话,返回一个操作数的方法要复杂得多,因为对于应该选择哪个操作数没有共识,尤其是当有两个以上的操作数时。例如,xor(None, -1, [], True)
应该返回 None
、[]
还是 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()
有时我发现自己使用 1 和 0 而不是布尔 True 和 False 值。在这种情况下,xor 可以定义为
z = (x + y) % 2
它具有以下真值表:
x
|0|1|
-+-+-+
0|0|1|
y -+-+-+
1|1|0|
-+-+-+
许多人,包括我自己,都需要一个 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
您使用与 C 中相同的 XOR 运算符,即 ^
。
我不知道为什么,但最受好评的解决方案建议 bool(A) != bool(B)
,而我会说 - 按照 C 的 ^
运算符,最明显的解决方案是:
bool(A) ^ bool(B)
对于来自 C
或任何 C
派生语言的任何人来说,这更具可读性和可立即理解...
在打代码打高尔夫球时,可能
not A ^ (not B)
将是赢家。用 not
作为布尔值的转换器(比 bool()
少一个字母。对于第一个表达式,在某些情况下可以省略括号。好吧,这取决于,在必须做 not(A) ^ (not(B))
的情况下,{ 2} 需要相同数量的字母...
not not A
是另一种无需函数调用即可获得与 bool(A)
相同结果的方法。
这个怎么样?
(not b and a) or (not a and b)
如果 b
为假,将给出 a
如果 a
为假,将给出 b
否则将给出 False
或者使用 Python 2.5+ 三元表达式:
(False if a else b) if b else a
Xor 在 Python 中是 ^
。它返回:
整数的按位异或
布尔的逻辑异或
集的排他并集
实现 __xor__ 的类的用户定义结果。
未定义类型的 TypeError,例如字符串或字典。
如果您打算在字符串上使用它们,将它们转换为 bool
会使您的操作明确(您也可以表示 set(str1) ^ set(str2)
)。
这就是我编写任何真值表的方式。特别是对于 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)
当您知道 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))
这将获得两个(或更多)变量的逻辑异或
str1 = raw_input("Enter string one:")
str2 = raw_input("Enter string two:")
any([str1, str2]) and not all([str1, str2])
这种设置的第一个问题是它很可能会遍历整个列表两次,并且至少会检查至少一个元素两次。因此它可能会提高代码理解能力,但不会提高速度(根据您的用例,差异可能可以忽略不计)。
此设置的第二个问题是它会检查排他性,而不考虑变量的数量。起初这可能被视为一个特征,但随着变量数量的增加(如果它们曾经这样做的话),第一个问题变得更加重要。
仅仅因为我没有在其他地方看到它,这也可以解决问题:
def logical_xor(a, b):
return not b if a else bool(b)
我不确定它是否比公认的解决方案 bool(a) != bool(b)“更好”/更具可读性/更 Pythonic。
Python 处理逻辑操作的方式可能会令人困惑,因此我的实现为用户提供了一个简单的 True/False 答案选项(默认情况下)。可以通过将可选的第三个 arg 设置为 None 来获得实际的 Python 结果。
def xor(a, b, true=True, false=False): # set true to None to get actual Python result
ab1 = a and not b
ab2 = not a and b
if bool(ab1) != bool(ab2):
return (ab1 or ab2) if true is None else true
else:
return false
这是一个概括。
def xor(*orands):
return sum(bool(x) for x in orands) == 1
你可以用
# test
from itertools import product
for a, b, c in product((False, True), repeat=3):
print(f'{int(a)}{int(b)}{int(c)}|{xor(a,b,c)}')
输出:
000|假 001|真 010|真 011|假 100|真 101|假 110|假 111|假
我们可以通过使用轻松找到两个变量的异或:
def xor(a,b):
return a !=b
例子:
异或(真,假)>>> 真
xor("hey", "there")
>>>没错,但这不是我们想要的
bool(a) is not bool(b)
吗?