Một số triển khai được đề xuất ở đây sẽ gây ra sự đánh giá lặp lại của các toán hạng trong một số trường hợp, điều này có thể dẫn đến các tác dụng phụ ngoài ý muốn và do đó phải tránh.
Điều đó nói rằng, xor
việc thực hiện trả về một trong hai True
hoặc False
khá đơn giản; một cái trả về một trong các toán hạng, nếu có thể, sẽ phức tạp hơn nhiều, bởi vì không có sự đồng thuận nào tồn tại như toán hạng nào nên được chọn, đặc biệt là khi có nhiều hơn hai toán hạng. Chẳng hạn, nên xor(None, -1, [], True)
trả lại None
, []
hay False
? Tôi đặt cược mỗi câu trả lời xuất hiện cho một số người là câu trả lời trực quan nhất.
Đối với kết quả Đúng hoặc Kết quả sai, có tối đa năm lựa chọn có thể: trả về toán hạng đầu tiên (nếu nó khớp với kết quả cuối cùng về giá trị, khác boolean), trả về kết quả khớp đầu tiên (nếu có ít nhất một tồn tại, khác boolean), trả về toán hạng cuối cùng (nếu ... khác ...), trả về kết quả cuối cùng (nếu ... khác ...) hoặc luôn trả về boolean. Nhìn chung, đó là 5 ** 2 = 25 hương vị của 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()