Que fait l'opérateur caret (^) en Python?

111

J'ai rencontré l'opérateur caret en python aujourd'hui et je l'ai essayé, j'ai obtenu le résultat suivant:

>>> 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
>>>

Il semble être basé sur 8, donc je suppose une sorte d'opération d'octet? Je n'arrive pas à trouver grand chose à propos de ces sites de recherche à part qu'il se comporte étrangement pour les flotteurs, est-ce que quelqu'un a un lien vers ce que fait cet opérateur ou pouvez-vous l'expliquer ici?

Frire
la source
4
Pour les entiers, la même chose est faite en C. ^ _-
Mike DeSimone
15
Pour info, à partir du shell python, vous pouvez taperhelp('^')
seth
6
Notez qu'il ne se comporte pas bizarrement pour les flottants (cela ne fonctionne tout simplement pas avec les flotteurs!). Notez également que de nombreuses personnes rencontrent accidentellement cela en recherchant **l'opérateur d'exponentiation.
Mike Graham
3
@seth: help('^')ne fait rien dans mon Python 2.6.1 (version Apple). @ S.Lott: voulez-vous dire ceci ( docs.python.org/reference/… ) quand vous dites "complètement couvert" ?. Semble un peu rare pour quelqu'un qui ne connaît pas le concept ...
ChristopheD
3
Merci à tous, je suppose que si j'avais su que c'était un opérateur au niveau du bit, j'aurais su exactement où chercher, mais je ne l'ai pas fait, d'où la question :) Merci à tous pour vos réponses, ils ont tous été utiles et maintenant j'en sais un peu plus ! :)
Fry

Réponses:

173

C'est un XOR au niveau du bit (OU exclusif).

Il en résulte vrai si un (et un seul) des opérandes (est évalué à) vrai.

Démontrer:

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

Pour expliquer l'un de vos propres exemples:

>>> 8^3
11

Pensez-y de cette façon:

1000 # 8 (binaire)
0011 # 3 (binaire)
---- # APPLY XOR ('verticalement')
1011 # résultat = 11 (binaire)
ChristopheD
la source
14
Un exemple un peu plus illustratif pourrait inclure les deux nombres ayant 1dans le même bit pour le préciser 1 xor 1 = 0.
Mike Graham
1
Je voulais ajouter, vous pouvez faire des nombres binaires en tapant 0bXoù X est votre binaire. 0b0001, 0b0010Etc. Alors, 0b1101 ^ 0b1110voulez - vous donner 0b0011(ou 3).
Jeff
Je pense que "Il en résulte vrai si un (et un seul) des opérandes (évalue à) vrai." n'est pas exact, ce serait la définition d'un xor booléen
Xavier Combelle
42

Il invoque la méthode __xor__()ou __rxor__()de l'objet si nécessaire, ce qui pour les types entiers effectue un ou exclusif au niveau du bit.

Ignacio Vazquez-Abrams
la source
4
+1 pour avoir souligné ce qu'il fait vraiment , en dehors de l'opération entière.
Mike DeSimone
8

De manière générale, le symbole ^est une version infixe des méthodes __xor__ou __rxor__. Quels que soient les types de données placés à droite et à gauche du symbole, ils doivent implémenter cette fonction de manière compatible. Pour les entiers, c'est l' XORopération courante , mais par exemple, il n'y a pas de définition intégrée de la fonction pour le type floatavec type 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'

Une chose intéressante à propos de Python est que vous pouvez remplacer ce comportement dans une classe de votre choix. Par exemple, dans certaines langues, le ^symbole signifie exponentiation. Vous pouvez le faire de cette façon, à titre d'exemple:

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

Ensuite, quelque chose comme ça fonctionnera, et maintenant, pour les instances de Fooseulement , le ^symbole signifiera l'exponentiation.

In [16]: x = Foo(3)

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

In [18]: x ^ 4
Out[18]: 81.0
ely
la source
woah, était-ce même possible? et pourrions-nous probablement changer le fonctionnement de l' +opérateur aussi?
K DawG
Oui, c'est ainsi que le +symbole est capable de faire un type d'action pour list(concaténation) tout en faisant un autre type d'action (addition mathématique) pour les types numériques. Dans ce cas, vous remplaceriez les méthodes __add__ou __radd__de votre classe.
ely
1
En remarque, la __r*__version de ceux-ci (comme __rxor__ou __radd__) sera invoquée à partir de l'argument apparaissant sur le côté droit du symbole infixe, et seulement si l'appel à la fonction pour le symbole de gauche ne fonctionne pas. Vous pouvez penser à cela comme try: left_hand_symbol.__xor__(right_hand_symbol); except: right_hand_symbol.__rxor__(left_hand_symbol), mais xorpeut être remplacé par l'un des opérateurs d'infixe disponibles dans le modèle de données Python .
ely
Cela signifie que je peux créer mon propre opérateur qui permet la intconcaténation avec des chaînes? mec, python est bien complexe que je ne le pensais
K DawG
1
Vous pourriez donc dire quelque chose comme (CompositionA | CompositionB) // CompositionCet cela signifierait simplement "Jouez la composition A suivie de la composition B, en même temps, jouez également la composition C en même temps en parallèle". Parlez d'un beau morceau de code!
ely
3

Lorsque vous utilisez l' ^opérateur, derrière les rideaux, la méthode __xor__est appelée.

a^béquivaut à a.__xor__(b).

Également, a ^= béquivaut à a = a.__ixor__(b)(où __xor__est utilisé comme solution de secours lorsque __ixor__est implicitement appelé via using ^=mais n'existe pas).

En principe, ce que __xor__fait dépend entièrement de sa mise en œuvre. Les cas d'utilisation courants en Python sont:

  • Différence symétrique des ensembles (tous les éléments présents dans exactement l'un des deux ensembles)

Démo:

>>> 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 pour les bits de deux entiers

Démo:

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

Explication:

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