¿Cómo se obtiene el xor lógico de dos variables en Python?

¿Cómo se obtiene el xor lógico de dos variables en Python?

Por ejemplo, tengo dos variables que espero sean cadenas. Quiero probar que solo uno de ellos contiene un valor Verdadero (no es Ninguno o la cadena vacía):

str1 = raw_input("Enter string one:") str2 = raw_input("Enter string two:") if logical_xor(str1, str2): print "ok" else: print "bad" 

El operador ^ parece ser bit a bit y no está definido en todos los objetos:

 >>> 1 ^ 1 0 >>> 2 ^ 1 3 >>> "abc" ^ "" Traceback (most recent call last): File "", line 1, in  TypeError: unsupported operand type(s) for ^: 'str' and 'str' 

    Si ya está normalizando las entradas a los valores booleanos, entonces! = Es xor.

     bool(a) != bool(b) 

    Siempre puede usar la definición de xor para calcularla a partir de otras operaciones lógicas:

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

    Pero esto es un poco demasiado detallado para mí, y no es particularmente claro a primera vista. Otra forma de hacerlo es:

     bool(a) ^ bool(b) 

    El operador xor en dos booleanos es xor lógico (a diferencia de los ints, donde es bitwise). Lo que tiene sentido, ya que bool es solo una subclase de int , pero se implementa para tener solo los valores 0 y 1 . Y xor lógico es equivalente a xor a nivel de bit cuando el dominio está restringido a 0 y 1 .

    Así que la función logical_xor se implementaría como:

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

    Crédito a Nick Coghlan en la lista de correo Python-3000 .

    Exclusivo o ya está integrado en Python, en el módulo del operator :

     from operator import xor xor(bool(a), bool(b)) 

    Como explicó Zach , puedes usar:

     xor = bool(a) ^ bool(b) 

    Personalmente, prefiero un dialecto ligeramente diferente:

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

    Este dialecto está inspirado en un lenguaje de diagtwigción lógica que aprendí en la escuela donde “OR” se denota por un cuadro que contiene ≥1 (mayor o igual a 1) y “XOR” se denota por un cuadro que contiene =1 .

    Esto tiene la ventaja de implementar correctamente exclusivos o en múltiples operandos.

    • “1 = a ^ b ^ c …” significa que el número de operandos verdaderos es impar. Este operador es la “paridad”.
    • “1 = a + b + c …” significa que exactamente un operando es verdadero. Esto es “exclusivo o”, que significa “uno a la exclusión de los otros”.
    • Python lógico or : A or B : devuelve A si bool(A) es True , de lo contrario devuelve B
    • Python lógico and : A and B : devuelve A si bool(A) es False , de lo contrario devuelve B

    Para mantener la mayor parte de esa forma de pensar, mi definición lógica o lógica sería:

     def logical_xor(a, b): if bool(a) == bool(b): return False else: return a or b 

    De esa manera puede devolver a , b , o False :

     >>> logical_xor('this', 'that') False >>> logical_xor('', '') False >>> logical_xor('this', '') 'this' >>> logical_xor('', 'that') 'that' 

    He probado varios enfoques y not a != (not b) parece ser el más rápido.

    Aquí hay algunas pruebas

     %timeit not a != (not b) 10000000 loops, best of 3: 78.5 ns per loop In [130]: %timeit bool(a) != bool(b) 1000000 loops, best of 3: 343 ns per loop In [131]: %timeit not a ^ (not b) 10000000 loops, best of 3: 131 ns per loop 

    Como no veo la variante simple de xor usando argumentos variables y solo operación en los valores de Verdadero Verdadero o Falso, simplemente lo lanzaré aquí para que lo use cualquier persona. Es como lo han señalado otros, bonito (por no decir muy) sencillo.

     def xor(*vars): sum = bool(False) for v in vars: sum = sum ^ bool(v) return sum 

    Y el uso también es sencillo:

     if xor(False, False, True, False): print "Hello World!" 

    Como este es el XOR lógico n-ario generalizado, su valor de verdad será Verdadero siempre que el número de operandos Verdaderos sea impar (y no solo cuando uno sea Verdadero, este es solo un caso en el que XOR n-aria es Verdadero).

    Por lo tanto, si está buscando un predicado n-ario que solo sea Verdadero cuando exista uno de sus operandos, es posible que desee utilizar:

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

    Hilo gratificante:

    Idea anodidora … Solo intente (puede ser) la expresión pythonica «no es» para obtener el comportamiento del «xor» lógico

    La tabla de verdad sería:

     >>> True is not True False >>> True is not False True >>> False is not True True >>> False is not False False >>> 

    Y para su cadena de ejemplo:

     >>> "abc" is not "" True >>> 'abc' is not 'abc' False >>> 'abc' is not '' True >>> '' is not 'abc' True >>> '' is not '' False >>> 

    Sin embargo; como se indicó anteriormente, depende del comportamiento real que desee extraer sobre cualquier par de cuerdas, porque las cuerdas no son boleanas … y aún más: si «Bucea en Python», encontrará «La naturaleza peculiar de” y “y” o ” http://www.diveintopython.net/power_of_introspection/and_or.html

    Lo siento mi inglés escrito, no es mi idioma de nacimiento.

    Saludos.

    Sé que esto es tarde, pero tuve un pensamiento y podría valer la pena, solo por documentación. Quizás esto funcione: np.abs(xy) La idea es que

    1. si x = Verdadero = 1 e y = Falso = 0, entonces el resultado sería | 1-0 | = 1 = Verdadero
    2. si x = Falso = 0 e y = Falso = 0, entonces el resultado sería | 0-0 | = 0 = Falso
    3. si x = True = 1 y y = True = 1 entonces el resultado sería | 1-1 | = 0 = Falso
    4. si x = False = 0 y y = True = 1 entonces el resultado sería | 0-1 | = 1 = True

    Exclusivo O se define como sigue

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

    ¿Qué tal esto?

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

    dará a si b es falso
    dará b si a es falso
    dará False contrario

    O con la expresión ternaria de Python 2.5+:

     (False if a else b) if b else a 

    Algunas de las implementaciones sugeridas aquí causarán una evaluación repetida de los operandos en algunos casos, lo que puede llevar a efectos secundarios no deseados y, por lo tanto, debe evitarse.

    Dicho esto, una implementación xor que devuelva True o False es bastante simple; El que devuelve uno de los operandos, si es posible, es mucho más complicado, ya que no existe un consenso sobre qué operando debe ser el elegido, especialmente cuando hay más de dos operandos. Por ejemplo, ¿debería xor(None, -1, [], True) devolver None , [] o False ? Apuesto a que cada respuesta parece ser la más intuitiva para algunas personas.

    Ya sea para el resultado Verdadero o Falso, hay hasta cinco opciones posibles: devolver el primer operando (si coincide con el resultado final en el valor, si no es booleano), devolver la primera coincidencia (si existe al menos uno, si es que es booleano), devuelve el último operando (si … más …), devuelve la última coincidencia (si … más …), o siempre devuelve booleano. En total, eso es 5 ** 2 = 25 sabores de 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() 

    A veces me encuentro trabajando con 1 y 0 en lugar de valores booleanos de verdadero y falso. En este caso xor puede definirse como

     z = (x + y) % 2 

    que tiene la siguiente tabla de verdad:

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

    Simple, fácil de entender:

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

    Si lo que está buscando es una opción exclusiva, puede expandirse a múltiples argumentos:

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

    Es fácil cuando sabes lo que hace 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 se implementa en operator.xor .

    Esto obtiene el XOR exclusivo lógico para dos (o más) variables

     str1 = raw_input("Enter string one:") str2 = raw_input("Enter string two:") any([str1, str2]) and not all([str1, str2]) 

    El primer problema con esta configuración es que lo más probable es que atraviese la lista completa dos veces y, como mínimo, verificará al menos uno de los elementos dos veces. Por lo tanto, puede boost la comprensión del código, pero no se presta a la velocidad (lo que puede diferir de manera despreciable según su caso de uso).

    El segundo problema con esta configuración es que comprueba la exclusividad independientemente del número de variables. Esto puede considerarse al principio como una característica, pero el primer problema se vuelve mucho más significativo a medida que aumenta el número de variables (si es que alguna vez lo hacen).

    Xor es ^ en Python. Vuelve :

    • Un xor bitwise para ints
    • Xor logico para bools
    • Un sindicato exclusivo para conjuntos.
    • Resultados definidos por el usuario para las clases que implementan __xor__ .
    • TypeError para tipos no definidos, como cadenas o diccionarios.

    De todos modos, si pretende usarlos en cadenas, convertirlos en bool hace que su operación sea inequívoca (también podría significar set(str1) ^ set(str2) ).

    Muchas personas, incluido yo mismo, necesitan una función xor que se comporte como un circuito xor de n entradas, donde n es variable. (Consulte https://en.wikipedia.org/wiki/XOR_gate ). La siguiente función simple implementa esto.

     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) 

    La muestra I / O sigue:

     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 

    Podemos encontrar fácilmente xor de dos variables mediante el uso de:

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

    Ejemplo:

    xor (Verdadero, Falso) >>> Verdadero