Je m’embrouille de plus en plus avec les operateur | et & en python. J’ai regarde pour les int, et j’ai vu que value1|value2 peut etre different de value2|value1. Pourtant
1
2
3
4
5
>>>1|23>>>2|13>>>
Je sais que chaque objet a sa propre interpretation des operateur grace a methode magique, mais globalement, ca a generalement le meme sens, non? (la seule exception que j’ai trouve est / avec pathlib)
Donc, c’est ca ma question: que veulent dire les operateurs & et |.
On prend la représentation des 2 nombres en binaire. Et on applique la règle précédante.
Si le niem bit du premier nombre est 1 et le niem bit du deuxième nombre est 1 alors ’&’ donnera un niem bit de 1, sinon ce niem bit serra 0.
Si le niem bit du premier nombre est 1 et le niem bit du deuxième nombre est 1 alors ’&’ donnera un niem bit de 1, sinon ce niem bit serra 0.
Si le niem bit du premier nombre est 0 et le niem bit du deuxième nombre est 0 alors ’|’ donnera un niem bit de 0, sinon ce niem bit serra 1.
Opérations bit à bit : https://fr.wikipedia.org/wiki/Opération_bit_à_bithttps://fr.wikipedia.org/wiki/Opération_bit_à_bit
Les versions de bases de | et & sont symétriques mais tu peux les surcharger pour que ce ne soit plus le cas. L’implémentation sur les entiers l’est elle.
Au sens purement mathématique (dans le sens courant hein, parce que bien sûr on peut définir ce qu’on veut en maths) == n’est pas une opération mais une relation (c’est pour ca qu’on la qualifie de symétrique et pas de commutative). Au sens programmatique, par contre, oui, == est un opérateur commutatif.
Peut-être que math2001 parlait du "court-circuit" ? Mais c’est or qui court-circuite en python, ce que ne fait pas |.
1
2
3
4
5
6
7
8
9
deftest(str,b):print(str)returnbtest("A",True)|test("B",True)# affiche "A" et "B"test("A",True)ortest("B",True)# affiche uniquement "A" et retourne directement True# puisque ça ne dépend pas de la valeur de test("B", True)
Il n’y a que l’ordre dans lequel sont évalués A et B qui change entre A | B et B | A.
Au sens purement mathématique (dans le sens courant hein, parce que bien sûr on peut définir ce qu’on veut en maths) == n’est pas une opération mais une relation (c’est pour ca qu’on la qualifie de symétrique et pas de commutative). Au sens programmatique, par contre, oui, == est un opérateur commutatif.
En general on definit la commutativite pour des fonctions $f : X \times X \to Y$ (ca veut dire $f(x, x') = f(x', x)$ pour tout $(x, x') \in X \times X$), donc ca a bien un sens "naturel" de dire == est commutatif, en voyant une relation comme une application d’un produit cartesien dans $\{0, 1\}$ par exemple (auquel cas il faut remarquer que (x == y) = (y == x), avec le = du milieu qui est le = mathematique… (x == y) == (y == x) exprime autre chose).
Dans ces circonstances il est equivalent de dire == est commutatif ou == est symetrique, mais bon, c’est du pinaillage pas tres essentiel, ca montre juste a quel point les deux notions sont proches. (Ca rentre en quelque sorte dans le "on peut definir ce qu’on veut en maths", mais en partant de ce constat la remarque de nohar n’est pas forcement justifiee non plus, donc bon… :p)
Un truc intéressant à noter à propos de | et de &, qui à ma connaissance n’est possible qu’en python, est qu’ils peuvent être utilisés sur des ensembles, également avec le sens de "et" (intersection) et de "ou" (union).
C’est un comportement plutôt intuitif et sympathique je trouve.
Bienvenue dans le monde des variables mutables. L’exemple peut paraître tiré par les cheveux, mais c’est le genre de problématique qui fait qu’il est impossible (pour un compilateur par exemple) de factoriser f(x) + f(x) en 2 * f(x) si on autorise f à avoir des effets de bords.
EDIT : je viens de réaliser que ça a une conséquence assez lourde en fait. Une application quelconque a beau être symétrique après évaluation de ses arguments, l’évaluation elle-même n’étant pas symétrique, il est impossible de garantir la symétrie de l’application.
Desole, j’ai pas eu le temps de poster mon message hier:
J’ai capte! Merci @ache et @tleb! Mais alors j’en vois pas l’ombre d’une utilite… Euh, comment on fait pour choper la representation en bit? J’ai vu des trucs comme ca 1 << 6, but it confuses me even more.
@etwanee et @blo yhg: ben maintenant, c’est ca qui me pose probleme. J’ai fais un coup de vieux help(int), et en regardant les functions methodes, je suis tombe la dessus:
Ah oui, je l’avais oublie c’ui la… Je regrette que % n’appelle pas .format, c’est plus rapide, et je trouve ca plus style.
@adri1: j’ai du mal a comprendre ton exemple. Les resultats sont differents juste parce que tu change les valeurs… Le | est toujours symetrique…
@QuentinC Je connaissais pas ca, merci! Mais c’est un comportement different ca, non? C’est pas a cause des bits non? (en relisant, on dirai que je dis que tu n’aurais pas du poster ton message, il est hors-sujet. Je tiens a preciser que ce n’est pas le cas )
Bon, au final, j’arrive maintenant avec deux questions:
pourquoi les int on deux differentes methodes puisqu’elles font la meme choses? Peut-etre c’est juste pour permettre a l’utilisateur de le faire dans n’importe quel ordre. Si c’est le cas, alors j’ai manque un truc sur les __magic__, il va falloir que j’y re-reflechisse.
quelle est l’utilite de ces operations sur les bits?
__rand__ et __and__ sont implémentées de façon à permettre un fallback à l’évaluation de a & b sur b.__rand__(a) si a.__and__(b) n’est pas implémentée.
@adri1: j’ai du mal a comprendre ton exemple. Les resultats sont differents juste parce que tu change les valeurs… Le | est toujours symetrique…
Ben tu vois bien que non. a[5] | b['val'] ne donne pas le même résultat que b['val'] | a[5]. De manière générale, tu n’as aucune garantie que expr1 | expr2 va donner le même résultat que expr2 | expr1 puisque l’évaluation de expr1 peut affecter celle de expr2 et inversement. | (ou n’importe quelle autre application qui devrait l’être) n’est symétrique que vis-à-vis de littéraux, pas dans le cas général.
Il me semble toutefois que cette surcharge est également possible en C++.
Oui, on peut certaiement écrire une fonction template<class T> std::set<T> operator& (const std::set<T>&, const std::set<T>&) , mais elle n’est pas disponible nativement.
Je connaissais pas ca, merci! Mais c’est un comportement different ca, non?
C’est différent, oui et non. Oui parce que c’est des opérations sur d’autres types. Mais au fond pour les nombres tu pourrais imaginer que tu travaille sur des ensembles de bits, un à un; ça pourrait t’aider à comprendre l’analogie, et voir qu’au final c’est pas si différent que ça.
Pour compléter le tableau, les opérations - et ^sont aussi disponibles pour les ensembles et calculent respectivement la différence et la différence symétrique.
On peut voir aussi assez facilement l’analogie entre la différence symétrique et le ou exclusif.
quelle est l’utilite de ces operations sur les bits?
Dans les utilisations classiques informatiques il y a le concept de champ de bits ou flags. Théoriquement avec des langages très haut niveau comme python on ne devrait plus le faire parce qu’il y a mieux et plus lisible, mais ça sert quand même toujours.
Mathématiquement, ça permet de faire des calculs plus rapides quand on travaille avec des puissances de 2. C’est plus rapide de faire des opérations sur les bits directement, plutôt que des multiplications et difisions.
Par exemple, x<<n équivaut à x*(2**n)et inversément, x>>n à x/(2**n). x%(2**n) peut être remplacé par x&(2**n-1), et 2**nlui-même peut être remplacé par 1<<n.
Enfin, x&~(2**n-1) permet de tronquer un nombre.
@adri1: Ok pour le fallback, c’est plus clair maintenant. A propos de ton example, j’avais capte, ce que je voulais dire c’etait que le resultat change parce que les valeurs finales changent, pas parce que l’ordre dans lequel elles sont. Desole, c’est qu’est pas ete tres fute sur ce coup…
@quentinC: Merci pour ces exemples sur les set. Donc, l’operateur & (et |) sont base sur le meme principe pour les bit et les set, mais pas le meme systems. Ok pour l’utilisation des bits, je ne pense avoir a m’en servir rapidement…
A propos de ton example, j’avais capte, ce que je voulais dire c’etait que le resultat change parce que les valeurs finales changent, pas parce que l’ordre dans lequel elles sont.
Mais les valeurs finales changent justement à cause de l’ordre dans lequel elles sont. C’est pour ça que dire que | ou + ou même == sont commutatifs, c’est aller un peu vite en besogne. Ce ne serait le cas que si l’ordre d’évaluation des expressions ne dépendait pas de leur position autour de l’opérateur, ou que l’ordre d’évaluation des expressions n’affectait pas leur valeur. La seule chose que l’on puisse dire, c’est que ces opérateurs sont commutatifs vis-à-vis de littéraux. Ce qui serait beaucoup plus intéressant serait la commutativité vis-à-vis d’expressions quelconques (donc la vraie commutativité au sens mathématique), ce qui est impossible en Python.
Connectez-vous pour pouvoir poster un message.
Connexion
Pas encore membre ?
Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte