Как вы получаете логическое xor двух переменных в Python?

Как вы получаете логический xor двух переменных в Python?

Например, у меня есть две переменные, которые я ожидаю быть строками. Я хочу проверить, что только один из них содержит значение True (не является ничем или пустой строкой):

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'

Ответ 1

Если вы уже нормализуете входы для булевых, то!= is xor.

bool(a) != bool(b)

Ответ 2

Вы всегда можете использовать определение xor для вычисления его из других логических операций:

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

Но это немного слишком много для меня, и на первый взгляд это не особенно понятно. Другой способ сделать это:

bool(a) ^ bool(b)

Оператор xor на двух логических операциях является логическим xor (в отличие от ints, где он побитовым). Это имеет смысл, так как bool является всего лишь подклассом int, но реализуется только для значений 0 и 1. И логический xor эквивалентен побитовому xor, когда домен ограничен 0 и 1.

Таким образом, функция logical_xor будет реализована так:

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

Кредит Ник Коглан в списке рассылки Python-3000.

Ответ 3

Побитовое исключение или уже встроено в Python в модуле operator (что идентично оператору ^):

from operator import xor
xor(bool(a), bool(b))  # Note: converting to bools is essential

Ответ 4

Как объясняется Зак, вы можете использовать:

xor = bool(a) ^ bool(b)

Лично я предпочитаю немного другой диалект:

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

Этот диалект вдохновлен логическим языком диаграмм, который я изучил в школе, где "OR" обозначался ящиком, содержащим ≥1 (больше или равным 1), а "XOR" обозначался ящиком, содержащим =1.

Это имеет то преимущество, что он правильно реализует эксклюзив или несколько операндов.

  • "1 = a ^ b ^ c..." означает, что число истинных операндов нечетно. Этот оператор является "четностью".
  • "1 = a + b + c..." означает, что один операнд имеет значение true. Это "эксклюзивный" или "означает" один, за исключением других ".

Ответ 5

  • Python logical or: A or B: возвращает A, если bool(A) is True, в противном случае возвращает B
  • Python logical and: A and B: возвращает A, если bool(A) is False, в противном случае возвращает B

Чтобы сохранить большую часть этого образа мышления, моя логическая xor-проверка была бы следующей:

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'

Ответ 6

Я протестировал несколько подходов, и 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

Edit: В примерах 1 и 3 выше отсутствуют круглые скобки, поэтому результат неверен. Новые результаты + функция truth(), как предложил ShadowRanger.

%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

Ответ 7

Награждение темы:

Идея анодера... Просто попробуйте (может быть) питонское выражение "нет", чтобы получить логическое поведение "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
>>> 

Тем не мение; как они указывали выше, это зависит от фактического поведения, которое вы хотите извлечь из любой пары строк, потому что строки не являются логическими значениями... и даже более того: если вы "Dive Into Python", вы найдете "Особую природу" и "и" или "" http://www.diveintopython.net/power_of_introspection/and_or.html

Извините мой английский, это не мой родной язык.

С уважением.

Ответ 8

Эксклюзивный или определяется следующим образом

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

Ответ 9

Поскольку я не вижу простого варианта xor, использующего переменные аргументы и только операции со значениями True, True или False, я просто брошу его здесь для любого использования. Это, как отмечают другие, довольно (если не сказать очень) просто.

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, это только один случай, когда n-арный XOR равен True).

Таким образом, если вы ищете n-арный предикат, который имеет значение True только тогда, когда есть только один из его операндов, вы можете использовать:

def isOne(*vars):
    sum = False
    for v in vars:
        if sum and v:
            return False
        else:
            sum = sum or v
    return sum

Ответ 10

Иногда мне приходится работать с 1 и 0 вместо логических значений True и False. В этом случае xor можно определить как

z = (x + y) % 2

который имеет следующую таблицу истинности:

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

Ответ 11

Я знаю, что это поздно, но я подумал, и это может стоить, просто для документации. Возможно, это сработало бы: np.abs(x-y) Идея в том, что

  • если x = True = 1 и y = False = 0, тогда результат будет равен | 1-0 | = 1 = True
  • если x = False = 0 и y = False = 0, тогда результат будет 0-0 | = 0 = False
  • если x = True = 1 и y = True = 1, тогда результат будет равен | 1-1 | = 0 = False
  • если x = False = 0 и y = True = 1, тогда результат будет равен | 0-1 | = 1 = True

Ответ 12

Просто, легко понять:

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

Если вам нужен эксклюзивный выбор, его можно расширить до нескольких аргументов:

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

Ответ 13

Как насчет этого?

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

даст a, если b false даст b, если a ложно
даст False иначе

Или с тернарным выражением Python 2.5+:

(False if a else b) if b else a

Ответ 14

Некоторые из предложенных здесь реализаций приведут к повторной оценке операндов в некоторых случаях, что может привести к непреднамеренным побочным эффектам, и поэтому их следует избегать.

Тем не менее, реализация xor, которая возвращает либо True, либо False, довольно проста; тот, который возвращает один из операндов, если это возможно, намного сложнее, потому что не существует консенсуса относительно того, какой операнд должен быть выбранным, особенно когда имеется более двух операндов. Например, если xor(None, -1, [], True) возвращает None, [] или False? Бьюсь об заклад, каждый ответ кажется некоторым людям наиболее интуитивным.

Для True или False-результата доступно до пяти возможных вариантов: возвратите первый операнд (если он соответствует конечному результату в значении, else boolean), верните первое совпадение (если хотя бы один существует, иначе boolean), вернуть последний операнд (если... else...), вернуть последнее соответствие (if... 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()

Ответ 15

Многим людям, включая меня, нужна функция 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)

Ниже приведен пример ввода/вывода:

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

Ответ 16

Легко, когда вы знаете, что делает 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))

Ответ 17

Это получает логический исключительный XOR для двух (или более) переменных

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

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

Первая проблема с этой установкой состоит в том, что она, скорее всего, пересекает весь список дважды и, как минимум, проверит хотя бы один из этих элементов дважды. Таким образом, это может увеличить понимание кода, но оно не дает скорости (что может незначительно отличаться в зависимости от вашего варианта использования).

Вторая проблема с этой установкой заключается в том, что она проверяет исключительность независимо от количества переменных. Сначала это можно рассматривать как функцию, но первая проблема становится намного более значительной, поскольку число переменных увеличивается (если они когда-либо).

Ответ 18

Xor это ^ в Python. Возвращает:

  • Побитовый xor для целых
  • Логический xor для bools
  • Эксклюзивный союз для наборов
  • Определяемые пользователем результаты для классов, которые реализуют __xor__.
  • Ошибка типа для неопределенных типов, таких как строки или словари.

Если вы все равно намереваетесь использовать их в строках, приведение их в bool делает вашу работу однозначной (вы также можете обозначить set(str1) ^ set(str2)).

Ответ 19

В Python есть побитовый оператор исключающего ИЛИ, это ^:

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

Вы можете использовать его, преобразовав входные данные в логические значения перед применением xor (^):

bool(a) ^ bool(b)

(отредактировано - спасибо, Арель)

Ответ 20

Чтобы получить логический xor двух или более переменных в Python:

  1. Преобразование входных данных в логические значения
  2. Используйте побитовый оператор xor (^ или operator.xor)

Например,

bool(a) ^ bool(b)

Когда вы конвертируете входные данные в логические значения, битовый xor становится логическим xor.

Обратите внимание, что принятый ответ неверен: != не совпадает с xor в Python из-за тонкости объединения операторов.

Например, xor из трех значений ниже является неправильным при использовании !=:

True ^  False ^  False  # True, as expected of XOR
True != False != False  # False! Equivalent to '(True != False) and (False != False)'

(P.S. я попытался отредактировать принятый ответ, чтобы включить это предупреждение, но мое изменение было отклонено.)

Ответ 21

XOR реализуется в operator.xor.

Ответ 22

Мы можем легко найти xor двух переменных, используя:

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

Пример:

xor (верно, неверно) >>> верно