¿Qué hace el operador de intercalación (^) en Python?

111

Me encontré con el operador de intercalación en python hoy y, al probarlo, obtuve el siguiente resultado:

>>> 8^3
11
>>> 8^4
12
>>> 8^1
9
>>> 8^0
8
>>> 7^1
6
>>> 7^2
5
>>> 7^7
0
>>> 7^8
15
>>> 9^1
8
>>> 16^1
17
>>> 15^1
14
>>>

Parece estar basado en 8, así que supongo que es algún tipo de operación de byte. Parece que no puedo encontrar mucho sobre estos sitios de búsqueda aparte de que se comporta de manera extraña para los flotadores, ¿alguien tiene un enlace a lo que hace este operador o puede explicarlo aquí?

Freír
fuente
4
Para enteros, lo mismo que en C. ^ _-
Mike DeSimone
15
Para su información, desde el caparazón de Python, puede escribirhelp('^')
seth
5
Tenga en cuenta que no se comporta de forma extraña con los flotantes (¡simplemente no funciona con los flotantes!). También tenga en cuenta que muchas personas se topan accidentalmente con esto mientras buscan **el operador de exponenciación.
Mike Graham
3
@seth: help('^')no hace nada en mi Python 2.6.1 (compilación de Apple). @ S.Lott: ¿te refieres a esto ( docs.python.org/reference/… ) cuando dices "completamente cubierto" ?. Parece un poco escaso para alguien que no esté familiarizado con el concepto ...
ChristopheD
3
Gracias a todos, supongo que si hubiera sabido que era un operador bit a bit, habría sabido dónde buscar, pero no lo hice, de ahí la pregunta :) Gracias a todos por sus respuestas, todos fueron útiles y ahora sé un poco más. ! :)
Fry

Respuestas:

173

Es un XOR bit a bit (OR exclusivo).

Resulta verdadero si uno (y solo uno) de los operandos (se evalúa como) verdadero.

Demostrar:

>>> 0^0
0
>>> 1^1
0
>>> 1^0
1
>>> 0^1
1

Para explicar uno de sus propios ejemplos:

>>> 8^3
11

Piensa en ello de esta manera:

1000 # 8 (binario)
0011 # 3 (binario)
---- # APLICAR XOR ('verticalmente')
1011 # resultado = 11 (binario)
Cristóbal
fuente
14
Un ejemplo un poco más ilustrativo podría incluir ambos números 1en el mismo bit para dejarlo en claro 1 xor 1 = 0.
Mike Graham
1
Quería agregar, puedes hacer números binarios escribiendo 0bXdonde X es tu binario. 0b0001, 0b0010, Etc Por lo tanto, 0b1101 ^ 0b1110sería darle 0b0011(o 3).
Jeff
Creo que "resulta verdadero si uno (y solo uno) de los operandos (se evalúa como) verdadero". no es exacto, cuál sería la definición de un xor booleano
Xavier Combelle
42

Invoca el método __xor__()o __rxor__()del objeto según sea necesario, que para los tipos enteros hace un exclusivo-or bit a bit.

Ignacio Vázquez-Abrams
fuente
4
+1 por señalar lo que realmente hace, fuera de la operación de números enteros.
Mike DeSimone
8

En términos generales, el símbolo ^es una versión infija de los métodos __xor__o __rxor__. Cualquier tipo de datos que se coloque a la derecha e izquierda del símbolo debe implementar esta función de una manera compatible. Para enteros, es la XORoperación común , pero por ejemplo, no hay una definición incorporada de la función para el tipo floatcon tipo int:

In [12]: 3 ^ 4
Out[12]: 7

In [13]: 3.3 ^ 4
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-13-858cc886783d> in <module>()
----> 1 3.3 ^ 4

TypeError: unsupported operand type(s) for ^: 'float' and 'int'

Una cosa interesante de Python es que puede anular este comportamiento en una clase propia. Por ejemplo, en algunos idiomas, el ^símbolo significa exponenciación. Puede hacerlo de esta manera, solo como un ejemplo:

class Foo(float):
    def __xor__(self, other):
        return self ** other

Entonces algo como esto va a funcionar, y ahora, para casos de Fooúnica , el ^símbolo significa exponenciación.

In [16]: x = Foo(3)

In [17]: x
Out[17]: 3.0

In [18]: x ^ 4
Out[18]: 81.0
ely
fuente
woah, ¿era eso posible? y probablemente también podríamos cambiar la forma en +que trabaja el operador?
K DawG
Sí, así es como el +símbolo puede realizar un tipo de acción para list(concatenación) mientras realiza otro tipo de acción (suma matemática) para tipos numéricos. En ese caso, anularía los métodos __add__o __radd__en su clase.
ely
1
Como nota al margen, la __r*__versión de estos (como __rxor__o __radd__) se invocará desde el argumento que aparece en el lado derecho del símbolo de infijo, y solo si la llamada a la función para el símbolo de la mano izquierda no funciona. Puede pensar en ello try: left_hand_symbol.__xor__(right_hand_symbol); except: right_hand_symbol.__rxor__(left_hand_symbol), pero xorpuede ser reemplazado por cualquiera de los operadores infijos disponibles en el modelo de datos de Python .
ely
¿Eso significa que puedo crear mi propio operador que permita la intconcatenación con cadenas? hombre, Python es mucho más complejo de lo que pensaba
K DawG
1
Así que podría decir algo como (CompositionA | CompositionB) // CompositionCy simplemente significaría "Reproducir la composición A seguida de la composición B, mientras tanto, también tocar la composición C al mismo tiempo en paralelo". ¡Habla de un hermoso código!
ely
3

Cuando usa el ^operador, detrás de las cortinas __xor__se llama al método .

a^bes equivalente a a.__xor__(b).

Además, a ^= bes equivalente a a = a.__ixor__(b)(donde __xor__se usa como respaldo cuando __ixor__se llama implícitamente mediante using ^=pero no existe).

En principio, lo que __xor__hace depende completamente de su implementación. Los casos de uso comunes en Python son:

  • Diferencia simétrica de conjuntos (todos los elementos presentes en exactamente uno de dos conjuntos)

Manifestación:

>>> a = {1, 2, 3}
>>> b = {1, 4, 5}
>>> a^b
{2, 3, 4, 5}
>>> a.symmetric_difference(b)
{2, 3, 4, 5}
  • Bitwise Non-Equal para los bits de dos enteros

Manifestación:

>>> a = 5
>>> b = 6
>>> a^b
3

Explicación:

    101 (5 decimal)
XOR 110 (6 decimal)
-------------------
    011 (3 decimal)
timgeb
fuente