O que o operador circunflexo (^) em Python faz?

111

Encontrei o operador circunflexo em python hoje e, ao experimentá-lo, obtive a seguinte saída:

>>> 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 ser baseado em 8, então estou supondo que algum tipo de operação de byte? Não consigo encontrar muito sobre esses sites de busca, exceto se ele se comporta de forma estranha para flutuadores, alguém tem um link para o que este operador faz ou você pode explicar isso aqui?

Fritar
fonte
4
Para inteiros, a mesma coisa que faz em C. ^ _-
Mike DeSimone
15
Para sua informação, no shell do python, você pode digitarhelp('^')
seth
6
Observe que ele não se comporta de maneira estranha para flutuadores (simplesmente não funciona com flutuadores!). Observe também que muitas pessoas acidentalmente se deparam com isso enquanto procuram **o operador de exponenciação.
Mike Graham,
3
@seth: help('^')não faz nada no meu Python 2.6.1 (compilação da apple). @ S.Lott: você quer dizer isso ( docs.python.org/reference/… ) quando está dizendo "completamente coberto"? Parece um pouco esparso para quem não está familiarizado com o conceito ...
ChristopheD
3
Obrigado a todos, acho que se eu soubesse que era um operador bit a bit, saberia exatamente onde procurar, mas não sabia, daí a pergunta :) Obrigado a todos por suas respostas, cada um foi útil e agora sei um pouco mais ! :)
Fry

Respostas:

173

É um XOR bit a bit (OU exclusivo).

Resulta verdadeiro se um (e apenas um) dos operandos (avalia como) verdadeiro.

Para demonstrar:

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

Para explicar um de seus próprios exemplos:

>>> 8^3
11

Pense nisso desta maneira:

1000 # 8 (binário)
0011 # 3 (binário)
---- # APLICAR XOR ('verticalmente')
1011 # resultado = 11 (binário)
ChristopheD
fonte
14
Um exemplo um pouco mais ilustrativo pode incluir ambos os números 1no mesmo bit para deixar isso claro 1 xor 1 = 0.
Mike Graham,
1
Eu queria adicionar, você pode fazer números binários digitando 0bXonde X é o seu binário. 0b0001, 0b0010etc. Então, 0b1101 ^ 0b1110daria a você 0b0011(ou 3).
Jeff
Eu penso "Isso resulta em verdadeiro se um (e apenas um) dos operandos (avaliar como) verdadeiro." não é exato, seria o que seria a definição de um xor booleano
Xavier Combelle
42

Ele invoca o método __xor__()ou __rxor__()do objeto conforme necessário, que para tipos inteiros faz um ou exclusivo bit a bit.

Ignacio Vazquez-Abrams
fonte
4
+1 para apontar o que realmente faz, fora da operação de inteiro.
Mike DeSimone
8

De um modo geral, o símbolo ^é uma versão infixa dos métodos __xor__ou __rxor__. Quaisquer tipos de dados colocados à direita e à esquerda do símbolo devem implementar essa função de maneira compatível. Para inteiros, é a XORoperação comum , mas por exemplo não há uma definição embutida da função para tipo floatcom 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'

Uma coisa legal sobre Python é que você pode sobrescrever esse comportamento em uma classe própria. Por exemplo, em alguns idiomas, o ^símbolo significa exponenciação. Você poderia fazer isso desta forma, apenas como um exemplo:

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

Em seguida, algo como isso vai funcionar, e agora, para instâncias de Fooúnica , o ^símbolo significa exponenciação.

In [16]: x = Foo(3)

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

In [18]: x ^ 4
Out[18]: 81.0
ely
fonte
woah, isso era mesmo possível? e poderíamos provavelmente mudar a forma como o +operador funciona também?
K DawG de
Sim, é assim que o +símbolo é capaz de fazer um tipo de ação para list(concatenação) enquanto executa outro tipo de ação (adição matemática) para tipos numéricos. Nesse caso, você substituiria os métodos __add__ou __radd__em sua classe.
ely
1
Como uma observação lateral, a __r*__versão destes (como __rxor__ou __radd__) será invocada a partir do argumento que aparece no lado direito do símbolo do infixo, e apenas se a chamada para a função do símbolo do lado esquerdo não funcionar. Você pode pensar nisso como try: left_hand_symbol.__xor__(right_hand_symbol); except: right_hand_symbol.__rxor__(left_hand_symbol), mas xorpode ser substituído por qualquer um dos operadores infixos disponíveis no Modelo de Dados Python .
ely
Isso significa que posso criar meu próprio operador, que permite a intconcatenação com strings? cara, python é muito mais complexo do que eu pensava
K DawG
1
Então, você poderia dizer algo como (CompositionA | CompositionB) // CompositionCe isso significaria apenas "Toque a composição A seguida pela composição B, enquanto isso, também toque a composição C ao mesmo tempo em paralelo." Fale sobre um belo trecho de código!
ely
3

Quando você usa o ^operador, nos bastidores, o método __xor__é chamado.

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

Além disso, a ^= bé equivalente a a = a.__ixor__(b)(onde __xor__é usado como substituto quando __ixor__é implicitamente chamado por meio de^= mas não existe).

Em princípio, __xor__depende totalmente de sua implementação. Casos de uso comuns em Python são:

  • Diferença simétrica de conjuntos (todos os elementos presentes em exatamente um dos dois conjuntos)

Demo:

>>> 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 os bits de dois inteiros

Demo:

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

Explicação:

    101 (5 decimal)
XOR 110 (6 decimal)
-------------------
    011 (3 decimal)
Timgeb
fonte