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

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

Например, у меня есть две переменные, которые я ожидаю быть строками. Я хочу проверить, что только один из них содержит значение 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'

Как вы определяете «xor» для пары строк? Как вы думаете, что должно вернуть "abc" ^ "", а что нет?

mmx 11.01.2009 15:39

Он должен возвращать True, а не вызывать исключение, поскольку только одна из строк имеет значение True, как определено обычным типом Python bool.

Zach Hirsch 11.01.2009 22:10

Я удивлен, что в Python нет инфиксного оператора под названием «xor», который был бы наиболее интуитивно понятной реализацией Pythonic. Использование «^» согласуется с другими языками, но не так очевидно читаемо, как большинство Python.

Mark E. Haase 11.11.2012 07:50

@MehrdadAfshari Очевидный ответ на ваш вопрос заключается в том, что a xor a определяется как (a and not b) or (not a and b), и поэтому a xor b, когда a и b являются символьными строками или любыми другими типами, должен давать все, что дает (a and not b) or (not a and b).

Kaz 14.05.2013 19:57

Проблема в том, что документация оставляет желать лучшего. ^ - это «побитовое исключающее ИЛИ», которое буквально интерпретируется как бит за битом, а не bool за bool. поэтому x'FFFF00 '^ x'FFFF00' должно быть x'000000 '. Или это должно происходить только по символам? преобразовать в числа? Нам нужно перебирать символы более короткой строки, чтобы она соответствовала длине более длинной строки. Все это должно быть встроено.

mckenzm 22.03.2015 05:29
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
753
5
851 051
25
Перейти к ответу Данный вопрос помечен как решенный

Ответы 25

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

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

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

bool(a) ^ bool(b)

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

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

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

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

отличный пост, но из всех способов назвать ваши параметры, почему 'str1' и 'str2'?

SingleNegationElimination 04.07.2009 20:55

@Token, почему бы и нет. Вы имеете в виду, потому что они не очень питонические?

orokusaki 25.01.2010 09:42

@orokusaki: потому что они, кажется, не очень хорошо предлагают предполагаемое использование.

SingleNegationElimination 28.01.2010 03:26

@Zach Hirsch Не могли бы вы использовать (не a и b) вместо (b, а не a) для удобства чтения, или определение будет несовместимо с xor.

orokusaki 01.02.2010 18:18

Вы должны сначала поставить nots, как этот (not b and a) or (not a and b), чтобы он возвращал строку, если она есть, что похоже на питонический способ работы функции.

rjmunro 08.05.2011 01:06

@TokenMacGuy: Что вы предлагали ему вместо этого назвать их?

user541686 14.06.2012 19:38

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

jpmc26 15.07.2019 21:49

Ваш ответ bool(a) ^ bool(b) гораздо яснее показывает намерение программиста xor, чем принятый в настоящее время ответ bool(a) != bool(b).

Guimoute 27.03.2021 16:33
  • Логический код Python or: A or B: возвращает A, если bool(A) - это True, в противном случае возвращает B
  • Логический код Python and: A and B: возвращает A, если bool(A) - это 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'

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

Zach Hirsch 11.01.2009 22:12

@ Zach Hirsch: Вот почему я сказал «сохранить наиболее такого образа мышления» - поскольку нет хорошего результата, когда оба истинны или ложны.

nosklo 26.11.2009 01:52

Логическая операция должна возвращать логическое значение, поэтому второе «return a или b» выглядит странно, поэтому второе return должно возвращать True.

Denis Barmenkov 10.02.2011 16:36

@ Денис Барменков: Обратите внимание, что логические операторы Python and и or не возвращают логическое значение. 'foo' and 'bar' возвращает 'bar' ...

nosklo 13.02.2011 05:11

На первый взгляд, два предыдущих ответа кажутся лучшими, но, если подумать, этот на самом деле единственный действительно правильный, то есть единственный, который предоставляет пример реализации xor, совместимой со встроенным and. и or. Однако, конечно, в практических ситуациях bool(a) ^ bool(b) или даже a ^ b (если известно, что a и b являются bool), конечно, более лаконичны.

Erik Kaplun 13.01.2012 17:48

Исключительное ИЛИ определяется следующим образом

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

который вернет True для xor ('this', '') и, чтобы следовать путем python, он должен вернуть 'this'.

nosklo 11.01.2009 16:45

@nosklo: Обсуди это с BDFL, пожалуйста, не я. Поскольку Python возвращает True, то должен будет способом Python.

S.Lott 11.01.2009 17:15

Я имею в виду согласованность с другими логическими операторами python - Python не возвращает True, когда я это делаю ('this' или ''), он возвращает 'this'. Но в вашей функции xor ('this', '') возвращает True. Он должен возвращать this, как и встроенная функция python.

nosklo 11.01.2009 18:09

Python and и or делают короткое замыкание. Любая реализация xor не может замыкать накоротко, так что несоответствие уже есть; следовательно, нет причин, по которым xor должен работать так же, как and + or.

tzot 12.01.2009 02:12

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

xor = bool(a) ^ bool(b)

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

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

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

Это дает преимущество правильной реализации исключительного или нескольких операндов.

  • «1 = a ^ b ^ c ...» означает, что количество истинных операндов нечетное. Это оператор «четности».
  • «1 = a + b + c ...» означает, что истинен ровно один операнд. Это «исключающее ИЛИ», означающее «одно исключение других».

Итак, True + True + False + True == 3 и 3! = 1, но True XOR True XOR False XOR True == True. Не могли бы вы подробнее рассказать о «правильной реализации XOR для нескольких операндов»?

tzot 12.01.2009 01:59

@ ΩΤΖΙΟΥ: завернуть в bool()

BlueRaja - Danny Pflughoeft 20.04.2010 17:26

@tzot Ваш пример не работает, потому что, согласно решению ddaa, вы применяете добавление только к двум переменным за раз. Так что правильный способ записать все это должен быть (((((True + True)==1)+False)==1)+True)==1. Приведенный здесь ответ полностью обобщается на несколько операндов.

ely 24.10.2012 01:18

Кроме того, существует разница между трехсторонним XOR и набором из двух XOR, сгруппированных по порядку операций. Итак, 3-WAY-XOR (A, B, C) - это нет, то же самое, что XOR (XOR (A, B), C). И пример ddaa - первое, а ваш - второе.

ely 24.10.2012 01:20

@EMS: спасибо. Ваши возражения прояснили (для меня), что означает ddaa.

tzot 25.10.2012 01:57

@ Mr.F Ваше объяснение не оправдывает этот ответ. В Python, если вы просто выполняете True + True + False + True, вы делать получаете 3, а True + True + False + True == 3 возвращает True, а True + True + False + True == 1 возвращает False. Другими словами, ответ здесь неверен; для этого вам необходимо проделать дополнительную работу. Между тем, простой True ^ True ^ False ^ True работает как положено.

jpmc26 14.08.2015 00:18

@ jpmc26 Я не понимаю вашего комментария. Подход сложения предназначен для обобщения операции, в которой вы хотите проверить, что операндом ровно один является True, множественное исключающее ИЛИ. Это другая операция, чем, например, A XOR B XOR ... XOR Z. Другими словами, если вы планируете использовать версию, основанную на сложении, то после отправки операндов в True + True + False + True вы должны ожидать, что результатом будет False, поскольку более чем один из них - это True, который работает, если условие проверяет наличие == 1.

ely 14.08.2015 03:40

Поэтому, когда вы пишете True + True + False + True == 1, возвращает False, что является правильным и желательным, если вы используете подход сложения. Возможно, я неправильно понимаю вашу точку зрения, но я не вижу, что не так. Ему решать, хочет ли человек ту или иную операцию, а для множественного XOR, это просто вопрос семантики, какая из этих операций «является XOR».

ely 14.08.2015 03:41

(bool (a) + bool (b) + bool (c))% 2 == 1 будет работать, но ^-ing не стоит.

minmaxavg 03.01.2016 15:09

Гарантирует ли язык, что bool (a) ^ bool (b) будет bool (а не просто int)? Если да, то где документально подтверждена гарантия? Спасибо.

Alan 28.11.2017 01:38

@ddaa Не понимаю почему. Это очень важно для вашего первого предложенного ответа.

Alan 28.11.2017 18:51

@ddaa Скажем так, это предположение, воплощенное в текущем поведении CPython. Я просто спрашиваю, знаете ли вы, какой тип будет возвращен вашим первым предложенным ответом в любой действующей реализации Python. Это простой вопрос, даже если у вас есть какое-то личное отвращение к is.

Alan 28.11.2017 21:02

Вы предполагаете, что существует такая вещь, как «допустимая реализация Python». Насколько я знаю, такого не существует. Поэтому ваш вопрос недействителен.

ddaa 30.11.2017 16:15

Действительно есть. Вот почему вы можете запускать одну и ту же программу Python на нескольких по-разному реализованных интерпретаторах.

DylanYoung 10.03.2020 00:06

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

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

выдаст a, если b ложный
выдаст b, если a ложно
даст False в противном случае

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

(False if a else b) if b else a
Ответ принят как подходящий

Если вы уже нормализуете входные данные до логических значений, то! = - это xor.

bool(a) != bool(b)

Хотя это умно и коротко, я не уверен, что это чисто. Когда кто-то читает эту конструкцию в коде, становится ли им сразу очевидно, что это операция xor? Я чувствовал себя обязанным добавить комментарий - знак для меня, что я пишу нечеткий код и пытаюсь извиниться с помощью комментария.

user188041 19.03.2012 21:25

Возможно, «ясно, что это XOR?» это неправильный вопрос. Мы просто пытались увидеть, одинаковы ли ответы на два вопроса, и думали, что будем использовать XOR для реализации этого. Например, если мы хотим убедиться, что мы не сравниваем яблоки с апельсинами, будет ли «if xor (isApple (x), isApple (y))» действительно яснее, чем «if isApple (x)! = IsApple (y)»? Не для меня!

AmigoNico 21.05.2012 22:27

Возникла проблема с использованием "! = " В качестве xor. Вы, вероятно, ожидаете, что bool (a)! = Bool (b)! = Bool (c) будет таким же, как bool (a) ^ bool (b) ^ bool (c). Так что делайте приведение в bool, но я бы порекомендовал ^. Чтобы узнать, что происходит в первом примере, найдите «цепочка операторов».

elmo 25.07.2012 15:50

@elmo: +1 за указание на разницу и +1 за то, что научил меня, что такое цепочка операторов! Я нахожусь в лагере, который говорит, что! = Не так читается, как ^.

Mark E. Haase 11.11.2012 07:58

Просто совет для таких простодушных, как я: будьте осторожны с приоритетом операторов! Я хотел проверить, обе ли две переменные равны нулю или обе не равны нулю, и в итоге написал (a is None != b is None). Что ж, это неправильно!

mrucci 22.09.2016 16:13

вместо этого должен быть bool(a) is not bool(b)?

RNA 14.02.2017 04:35

Это настоящий ответ? Я пробую этот код на своей машине, print bool("Hellow World") == bool("H"), он возвращает True

Jason 27.04.2018 20:07

@Jason Вы используете == вместо !=. При необходимости можно проверить перебором: for b1, b2 in ((True, False), (True, True), (False, False): assert (b1 != b2) == (b1 ^ b1). Это проверка по таблице истинности (с учетом коммутативности оператора). Я оставлю это как упражнение для проверки с помощью правил вывода;)

DylanYoung 07.12.2018 19:29

Мало того, что это затрудняет понимание кода, как указывает @elmo, это НЕ эквивалентно операции xor и может привести к трудно обнаруживаемым ошибкам в коде. operator.xor будет лучшей альтернативой.

ɹɐʎɯɐʞ 13.02.2019 19:58

Голосование вниз, потому что этот ответ НЕПРАВИЛЬНЫЙ (поскольку, как указано @elmo !=, не является XOR в python)

Arel 25.07.2019 15:38

@Arel: Для bool, для единственного сравнения, != точно такой же, как xor. Это только для связанного случая, когда поведение отличается. Не стоит отрицать.

ShadowRanger 26.09.2019 21:12

@ShadowRanger xor (^) - это xor. Не-равно (!=) не является xor в Python по тонкой причине, которая могла быть разъяснена в ответе, но не была. Вы правы, что он работает в случае с двумя переменными, как задается вопрос, но утверждение, что != является xor, неточно и ненужно. Я пытался отредактировать этот вопрос (дважды), чтобы добавить пояснение, но рецензенты отклонили мои изменения. Следовательно, голос против.

Arel 01.11.2019 05:01

Зачем обвинять респондента в плохих рецензентах?

DylanYoung 09.03.2020 17:14

@RNA Нет, не сравнивайте логические значения с is. Этот ответ объясняет, почему во втором разделе. PEP 8 также упоминает об этом, но не объясняет.

wjandrea 14.07.2020 02:02

@wjandrea Этот пост кажется неполным для bool(x) is True. Мы можем быть уверены, что значение, возвращаемое bool, будет либо True, либо False.

Josiah Yoder 27.07.2020 21:52

@Josiah Да, но мы не можем быть уверены, что True is True, потому что это деталь реализации.

wjandrea 27.07.2020 22:13

@Josiah О, да, ответ, который я связал, должен быть неправильным или устаревшим. Тем не менее, сравнение на равенство более интуитивно понятно, чем сравнение идентичности, хотя они делают то же самое для двух bool.

wjandrea 27.07.2020 22:23

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

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

Для истинного или ложного результата существует до пяти возможных вариантов: вернуть первый операнд (если он соответствует конечному результату по значению, иначе логическое значение), вернуть первое совпадение (если хотя бы один существует, иначе логическое значение), возвращать последний операнд (если ... еще ...), возвращать последнее совпадение (если ... еще ...) или всегда возвращать логическое значение. В целом, это 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()

Поскольку я не вижу простого варианта 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 всякий раз, когда количество истинных операндов нечетное (и не только когда точно один из них истинен, это всего лишь один случай, когда 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 в этих строках.

pathunstrom 25.04.2015 09:01

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

XOR реализован в operator.xor.

operator.xor соответствует побитовой операции, которая не нужна исходному плакату.

Niriel 07.05.2012 16:30

@kojiro видимо так!

Arel 25.07.2019 17:16

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

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

Это то, что мне было нужно. При обратном проектировании вредоносного ПО много раз строки искажаются до операции XOR. Используя это chr (xor (ord ("n"), 0x1A)) = 't'

ril3y 11.07.2012 18:15

Будьте осторожны, это тоже побитовое: xor(1, 2) возвращает 3. Из строки документации: xor(a, b) -- Same as a ^ b. Помните, что все, что импортировано из operator, является просто функциональной формой существующего встроенного инфиксного оператора.

askewchan 15.09.2013 20:59

@askewchan: Тип bool перегружает __xor__ для возврата логических значений. Он будет работать нормально, но когда bool(a) ^ bool(b) делает то же самое, это перебор.

Martijn Pieters 03.11.2014 15:48

@MartijnPieters Оператор ^ вызывает внутренний вызов __xor__.

Quantum7 15.02.2018 11:41

@ Quantum7: да, я не совсем понимаю, почему вы мне это говорите. Я только что сказал, что тип bool реализует метод __xor__особенно потому, что ^ называет это. Дело в том, что bool(a) ^ bool(b) работает нормально, здесь нет необходимости использовать функцию operator.xor().

Martijn Pieters 15.02.2018 17:21

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

z = (x + y) % 2

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

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

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

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

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

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

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

Я протестировал несколько подходов, и 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 выше скобки отсутствуют, поэтому результат неверен. Новые результаты + функция 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

Я не верну 100 нс моей жизни ;-)

Arel 25.07.2019 17:13

Для промежуточной синхронизации вы можете сделать from operator import truth в верхней части модуля и протестировать truth(a) != truth(b). bool, будучи конструктором, имеет много неизбежных накладных расходов на уровне C (он должен принимать аргументы как эквивалент *args, **kwargs и анализировать tuple и dict для их извлечения), где truth (будучи функцией) может использовать оптимизированный путь, который не Они требуют либо tuple, либо dict, и работают примерно в два раза быстрее, чем решения на основе bool (но все же дольше, чем решения на основе not).

ShadowRanger 26.09.2019 21:19

Награждение ветки:

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

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

С Уважением.

Я также использую, чтобы читать это как «строго другое». Это потому, что некоторые языки используют для побитовой реализации операции двоичного представления и принимают логическое значение результирующей побитовой операции. Думаю, ваш ответ более «пуленепробиваемый», потому что он выходит за рамки логического пространства.

yucer 28.03.2019 20:23

Я имею в виду тот факт, что ваш ответ касается случая сравнения None, False '', поскольку различие - это отличительный материал. Например: bool (False)! = Bool (''), тем не менее, False не '' "больше согласуется с семантикой" строго различного "

yucer 28.03.2019 20:24

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

  1. если x = True = 1 и y = False = 0, то результат будет | 1-0 | = 1 = True
  2. если x = False = 0 и y = False = 0, то результат будет | 0-0 | = 0 = False
  3. если x = True = 1 и y = True = 1, то результат будет | 1-1 | = 0 = False
  4. если x = False = 0 и y = True = 1, то результат будет | 0-1 | = 1 = True

Вы даже можете отказаться от abs, python интерпретирует отрицательные числа как правду, хотя это очень непонятно, imo (что означает if (x > 1) - (y > 3)?

Nearoo 03.10.2020 17:04

Просто, понятно:

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

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

sum(bool(x) for x in y) == 1
sum(map(bool, y)) % 2 == 1
warvariuc 07.09.2019 17:10

Я не вижу смысла использовать sum, если у вас всего две переменные, bool(a) + bool(b) == 1 делает то же самое.

Boris 14.02.2021 23:54

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

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

Пример:

xor(True,False) >>> True

или xor("hey", "there") >>> Верно, но мы этого не хотим

Mayou36 11.12.2018 12:35

Xor - это ^ в Python. Он возвращает:

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

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

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

Ниже приводится пример ввода / вывода:

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

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

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

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

bool(a) ^ bool(b)

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

В вашем ответе должно быть ясно, что ^ - это xor побитовый (не логический xor, как заданный вопрос). bool(2) ^ bool(3) дает другой ответ, чем bool(2 ^ 3).

Arel 18.07.2019 17:08

@Arel Но это не так. a ^ b является полиморфом. Если a и b являются экземплярами bool, результатом также будет bool. Такое поведение сложно назвать «побитовым» xor.

Alfe 15.08.2019 13:19

@Alfe важным моментом является то, что значения должны быть сначала преобразованы в логические. Документация Python определяет ^ как побитовое, хотя интересно, что типы сохраняются для типов bool и int. Примечание: True ^ 2 - это 3, демонстрируя, как это действительно поразрядно.

Arel 17.08.2019 09:03

@Arel Да, корпус bool ^ int в первую очередь перекладывает все на int. Тем не менее, Python имеет встроенный оператор ^ для многих битов в int и для одного бита, представленного в bool, так что оба являются побитовый, но побитовый xor для одного бита просто является xor логичный для логических значений.

Alfe 19.08.2019 14:52

Я всегда ненавижу использовать этот оператор, хотя я понимаю, что это xor, из инженерного опыта, мне это инстинктивно кажется математической силой, то есть 2^3 = pow(2,3), что означает, что я всегда прямо комментирую, чтобы избежать путаницы.

Nicholas Hamilton 09.09.2019 02:52

Чтобы получить логический 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. Я попытался отредактировать принятый ответ, чтобы включить это предупреждение, но мое изменение было отклонено.)

Вот как я бы кодировал любую таблицу истинности. В частности, для 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)
def xor(*args):
    return sum(bool(arg) for arg in args)%2

если вы хотите только одну истину:

def onlyOne(*args):
    return sum(bool(arg) for arg in args)==1

Это не xor, когда len(args) больше 2

HKTonyLee 05.12.2020 03:36

Способ, которым Python обрабатывает логические операции, может сбивать с толку, поэтому моя реализация дает пользователю возможность (по умолчанию) простого ответа True / False. Фактический результат Python можно получить, установив для необязательного третьего аргумента значение None.

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

Другие вопросы по теме