如何在Python中得到兩個變量的邏輯異或? ide
例如,我有兩個指望是字符串的變量。 我想測試其中只有一個包含True值(不是None或空字符串): 測試
str1 = raw_input("Enter string one:") str2 = raw_input("Enter string two:") if logical_xor(str1, str2): print "ok" else: print "bad"
^
運算符彷佛是按位的,而且未在全部對象上定義: lua
>>> 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'
此處建議的某些實如今某些狀況下會致使對操做數的重複評估,這可能致使意外的反作用,所以必須避免。 spa
也就是說,返回True
或False
的xor
實現很是簡單; 若是可能的話,返回一個操做數之一的技巧很是棘手,由於對於選擇哪一個操做數沒有共識,尤爲是當有兩個以上的操做數時。 例如, xor(None, -1, [], True)
返回None
, []
或False
? 我敢打賭,對於某些人來講,每一個答案都是最直觀的答案。 code
對於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()
位 operator
模塊(與^
運算符相同)已經內置在Python中的按位異或運算符: 字符串
from operator import xor xor(bool(a), bool(b)) # Note: converting to bools is essential
有時我發現本身使用1和0代替布爾True和False值。 在這種狀況下,xor能夠定義爲 get
z = (x + y) % 2
它具備如下真值表: input
x |0|1| -+-+-+ 0|0|1| y -+-+-+ 1|1|0| -+-+-+
由於我看不到使用變量參數的xor的簡單變體,而只對True值True或False進行運算,因此我將其扔給任何人使用。 正如其餘人所指出的那樣,它很是漂亮(不是很清楚)。 string
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
這將對兩個(或多個)變量進行邏輯異或
str1 = raw_input("Enter string one:") str2 = raw_input("Enter string two:") any([str1, str2]) and not all([str1, str2])
這種設置的第一個問題是,它極可能遍歷整個列表兩次,而且至少會兩次檢查至少一個元素。 所以,它可能會提升代碼的理解能力,但並不能提升速度(根據您的使用狀況而可能有所不一樣)。
此設置的第二個問題是,不管變量數量如何,它都會檢查排他性。 乍一看,這多是一個功能,可是隨着變量數量的增長(若是有的話),第一個問題變得更加劇要。