Qu'est-ce qui explique la différence de comportement des opérations booléennes et binaires sur les listes par rapport aux tableaux NumPy?
Je ne sais pas comment utiliser correctement &
vs and
en Python, illustré dans les exemples suivants.
mylist1 = [True, True, True, False, True]
mylist2 = [False, True, False, True, False]
>>> len(mylist1) == len(mylist2)
True
# ---- Example 1 ----
>>> mylist1 and mylist2
[False, True, False, True, False]
# I would have expected [False, True, False, False, False]
# ---- Example 2 ----
>>> mylist1 & mylist2
TypeError: unsupported operand type(s) for &: 'list' and 'list'
# Why not just like example 1?
>>> import numpy as np
# ---- Example 3 ----
>>> np.array(mylist1) and np.array(mylist2)
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
# Why not just like Example 4?
# ---- Example 4 ----
>>> np.array(mylist1) & np.array(mylist2)
array([False, True, False, False, False], dtype=bool)
# This is the output I was expecting!
Cette réponse et cette réponse m'ont aidé à comprendre qu'il and
s'agit d'une opération booléenne, mais d' &
une opération au niveau du bit.
J'ai lu sur les opérations au niveau du bit pour mieux comprendre le concept, mais j'ai du mal à utiliser ces informations pour donner un sens à mes 4 exemples ci-dessus.
Exemple 4 m'a conduit à ma sortie désirée, de sorte que c'est très bien, mais je suis encore confus quand / comment / pourquoi je devrais utiliser and
vs &
. Pourquoi les listes et les tableaux NumPy se comportent-ils différemment avec ces opérateurs?
Quelqu'un peut-il m'aider à comprendre la différence entre les opérations booléennes et binaires pour expliquer pourquoi ils gèrent différemment les listes et les tableaux NumPy?
np.bitwise_and()
etnp.logical_and()
et des amis pour éviter toute confusion.mylist1 and mylist2
ne produit pas le même résultat quemylist2 and mylist1
, puisque ce qui est renvoyé est la deuxième liste comme indiqué par delnan.Réponses:
and
teste si les deux expressions sont logiquementTrue
tandis que&
(lorsqu'il est utilisé avecTrue
/False
values) teste si les deux le sontTrue
.En Python, les objets intégrés vides sont généralement traités comme logiquement
False
tandis que les objets intégrés non vides le sont logiquementTrue
. Cela facilite le cas d'utilisation courant où vous voulez faire quelque chose si une liste est vide et autre chose si la liste ne l'est pas. Notez que cela signifie que la liste [False] est logiquementTrue
:Ainsi, dans l'exemple 1, la première liste est non vide et donc logiquement
True
, donc la valeur de vérité deand
est la même que celle de la deuxième liste. (Dans notre cas, la deuxième liste n'est pas vide et donc logiquementTrue
, mais identifier cela nécessiterait une étape de calcul inutile.)Par exemple 2, les listes ne peuvent pas être combinées de manière significative de manière binaire car elles peuvent contenir des éléments arbitraires contrairement à. Les éléments pouvant être combinés au niveau du bit incluent: les vrais et les faux, les entiers.
Les objets NumPy, en revanche, prennent en charge les calculs vectorisés. Autrement dit, ils vous permettent d'effectuer les mêmes opérations sur plusieurs éléments de données.
L'exemple 3 échoue car les tableaux NumPy (de longueur> 1) n'ont pas de valeur de vérité car cela évite la confusion de la logique vectorielle.
L'exemple 4 est simplement une
and
opération bit vectorisée .Conclusion
Si vous ne travaillez pas avec des tableaux et n'effectuez pas de manipulations mathématiques d'entiers, vous le souhaitez probablement
and
.Si vous avez des vecteurs de valeurs de vérité que vous souhaitez combiner, utilisez
numpy
avec&
.la source
À propos
list
D'abord un point très important, d'où tout découlera (j'espère).
En Python ordinaire, ce
list
n'est en aucun cas spécial (sauf avoir une syntaxe mignonne pour la construction, ce qui est principalement un accident historique). Une fois qu'une liste[3,2,6]
est faite, c'est à toutes fins utiles juste un objet Python ordinaire, comme un nombre3
, un ensemble{3,7}
ou une fonctionlambda x: x+5
.(Oui, il prend en charge la modification de ses éléments, et il prend en charge l'itération, et bien d'autres choses, mais c'est exactement ce qu'est un type: il prend en charge certaines opérations, sans en supporter d'autres. Int prend en charge l'élévation à une puissance, mais ce n'est pas le cas rendez-le très spécial - c'est exactement ce qu'est un int. lambda prend en charge les appels, mais cela ne le rend pas très spécial - c'est à cela que sert lambda, après tout :).
À propos
and
and
n'est pas un opérateur (vous pouvez l'appeler "opérateur", mais vous pouvez également appeler "for" un opérateur :). Les opérateurs en Python sont (implémentés via) des méthodes appelées sur des objets d'un certain type, généralement écrits dans le cadre de ce type. Il n'y a aucun moyen pour une méthode de tenir une évaluation de certains de ses opérandes, maisand
peut (et doit) le faire.La conséquence de cela est que
and
cela ne peut pas être surchargé, tout commefor
ne peut pas être surchargé. Il est complètement général et communique via un protocole spécifié. Ce que vous pouvez faire est de personnaliser votre partie du protocole, mais cela ne signifie pas que vous pouvez modifierand
complètement le comportement de . Le protocole est:Imaginez Python interprétant "a et b" (cela ne se produit pas littéralement de cette façon, mais cela aide à comprendre). Quand il s'agit de "et", il regarde l'objet qu'il vient d'évaluer (a), et lui demande: êtes-vous vrai? ( PAS : l'êtes-vous
True
?) Si vous êtes un auteur de la classe de a, vous pouvez personnaliser cette réponse. Sia
répond «non»,and
(saute complètement b, il n'est pas évalué du tout, et) dit:a
est mon résultat ( PAS : faux est mon résultat).Si
a
ne répond pas,and
lui demande: quelle est votre longueur? (Encore une fois, vous pouvez personnaliser cela en tant qu'auteur dea
la classe de). Si laa
réponse est 0,and
fait la même chose que ci-dessus - considère que c'est faux ( PAS faux), saute b et donnea
comme résultat.Si
a
répond autre chose que 0 à la deuxième question ("quelle est votre longueur"), ou s'il ne répond pas du tout, ou s'il répond "oui" à la première ("êtes-vous vrai"),and
évalue b, et dit:b
est mon résultat. Notez qu'il ne pose PASb
de questions.L'autre façon de dire tout cela est que
a and b
c'est presque la même chose queb if a else a
, sauf que a n'est évalué qu'une seule fois.Maintenant, asseyez-vous pendant quelques minutes avec un stylo et du papier, et convainquez-vous que lorsque {a, b} est un sous-ensemble de {True, False}, cela fonctionne exactement comme vous vous attendez des opérateurs booléens. Mais j'espère vous avoir convaincu que c'est beaucoup plus général, et comme vous le verrez, beaucoup plus utile de cette façon.
Mettre ces deux ensemble
J'espère que vous comprenez votre exemple 1.
and
ne se soucie pas si mylist1 est un nombre, une liste, un lambda ou un objet d'une classe Argmhbl. Il se soucie juste de la réponse de mylist1 aux questions du protocole. Et bien sûr, mylist1 répond à 5 à la question sur la longueur, donc et renvoie mylist2. Et c'est tout. Cela n'a rien à voir avec les éléments de mylist1 et mylist2 - ils n'entrent nulle part dans l'image.Deuxième exemple:
&
surlist
En revanche,
&
c'est un opérateur comme les autres, comme+
par exemple. Il peut être défini pour un type en définissant une méthode spéciale sur cette classe.int
le définit comme "et" au niveau du bit, et bool le définit comme "et" logique, mais ce n'est qu'une option: par exemple, les ensembles et certains autres objets comme les vues de clés dict le définissent comme une intersection d'ensemble.list
ne le définit tout simplement pas, probablement parce que Guido n'a pensé à aucun moyen évident de le définir.engourdi
De l'autre côté: -D, les tableaux numpy sont spéciaux, ou du moins ils essaient de l'être. Bien sûr, numpy.array est juste une classe, il ne peut
and
en aucun cas remplacer , donc il fait la meilleure chose suivante: quand on lui demande "êtes-vous vrai", numpy.array lève une ValueError, en disant effectivement "veuillez reformuler la question, mon la vision de la vérité ne rentre pas dans votre modèle ». (Notez que le message ValueError ne parle pasand
- car numpy.array ne sait pas qui lui pose la question; il parle juste de la vérité.)Car
&
, c'est une histoire complètement différente. numpy.array peut le définir comme il le souhaite, et il définit de manière&
cohérente avec les autres opérateurs: point par point. Donc, vous obtenez enfin ce que vous voulez.HTH,
la source
Les opérateurs booléens de court-circuit (
and
,or
) ne peuvent pas être remplacés car il n'y a pas de moyen satisfaisant de le faire sans introduire de nouvelles fonctionnalités de langage ou sacrifier le court-circuit. Comme vous le savez peut-être ou non, ils évaluent le premier opérande pour sa valeur de vérité et, en fonction de cette valeur, évaluent et renvoient le deuxième argument, ou n'évaluent pas le deuxième argument et renvoient le premier:Notez que le (résultat de l'évaluation de) l'opérande réel est renvoyé, et non sa valeur de vérité.
Le seul moyen de personnaliser leur comportement est de remplacer
__nonzero__
(renommé__bool__
en Python 3), de sorte que vous puissiez affecter l'opérande retourné, mais pas retourner quelque chose de différent. Les listes (et autres collections) sont définies comme étant «véridiques» lorsqu'elles contiennent quelque chose du tout, et «fausses» lorsqu'elles sont vides.Les tableaux NumPy rejettent cette notion: pour les cas d'utilisation auxquels ils visent, deux notions différentes de vérité sont communes: (1) si un élément est vrai, et (2) si tous les éléments sont vrais. Étant donné que ces deux éléments sont complètement (et silencieusement) incompatibles, et qu'aucun n'est clairement plus correct ou plus courant, NumPy refuse de deviner et vous oblige à utiliser explicitement
.any()
ou.all()
.&
et|
(etnot
, au fait) peuvent être entièrement annulés, car ils ne court-circuitent pas. Ils peuvent renvoyer n'importe quoi lorsqu'ils sont surchargés, et NumPy en fait bon usage pour effectuer des opérations élémentaires, comme ils le font avec pratiquement toute autre opération scalaire. Les listes, en revanche, ne diffusent pas d'opérations sur leurs éléments. Tout commemylist1 - mylist2
ne veut rien dire etmylist1 + mylist2
signifie quelque chose de complètement différent, il n'y a pas d'&
opérateur pour les listes.la source
[False] or [True]
évaluation[False]
et l’[False] and [True]
évaluation[True]
.Exemple 1:
C'est ainsi que fonctionne l' opérateur and .
x et y => si x est faux, alors x , sinon y
Donc, en d'autres termes, puisque
mylist1
n'est pasFalse
, le résultat de l'expression estmylist2
. (Seules les listes vides sont évaluéesFalse
.)Exemple 2:
L'
&
opérateur est pour un bit et, comme vous le mentionnez. Les opérations au niveau du bit ne fonctionnent que sur les nombres. Le résultat de a & b est un nombre composé de 1 en bits qui valent 1 à la fois en a et en b . Par exemple:Il est plus facile de voir ce qui se passe en utilisant un littéral binaire (mêmes nombres que ci-dessus):
Les opérations au niveau du bit sont similaires dans leur concept aux opérations booléennes (vérité), mais elles ne fonctionnent que sur des bits.
Donc, compte tenu de quelques déclarations sur ma voiture
Le "et" logique de ces deux déclarations est:
Les deux sont vrais, du moins pour ma voiture. La valeur de l'énoncé dans son ensemble est donc logiquement vraie.
Le "et" au niveau du bit de ces deux déclarations est un peu plus nébuleux:
Si python sait comment convertir les instructions en valeurs numériques, alors il le fera et calculera le bit et des deux valeurs. Cela peut vous amener à croire que
&
c'est interchangeable avecand
, mais comme dans l'exemple ci-dessus, ce sont des choses différentes. De plus, pour les objets qui ne peuvent pas être convertis, vous obtiendrez simplement un fichierTypeError
.Exemple 3 et 4:
Numpy implémente des opérations arithmétiques pour les tableaux:
Mais n'implémente pas d'opérations logiques pour les tableaux, car vous ne pouvez pas surcharger les opérateurs logiques en python . C'est pourquoi l'exemple trois ne fonctionne pas, mais l'exemple quatre fonctionne.
Donc, pour répondre à votre question
and
vs&
: utilisezand
.Les opérations au niveau du bit sont utilisées pour examiner la structure d'un nombre (quels bits sont définis, quels bits ne sont pas définis). Ce type d'informations est principalement utilisé dans les interfaces de système d'exploitation de bas niveau ( bits d'autorisation Unix , par exemple). La plupart des programmes python n'auront pas besoin de le savoir.
Les opérations logiques (
and
,or
,not
), cependant, sont utilisés tout le temps.la source
En Python, une expression de
X and Y
retoursY
, étant donné quebool(X) == True
ou l'un deX
ouY
évalué à False, par exemple:L'opérateur au niveau du bit n'est tout simplement pas défini pour les listes. Mais il est défini pour les entiers - fonctionnant sur la représentation binaire des nombres. Considérez 16 (01000) et 31 (11111):
NumPy n'est pas un médium, il ne sait pas si vous voulez dire que par exemple
[False, False]
devrait être égal àTrue
dans une expression logique. En cela, il remplace un comportement Python standard, qui est: "Toute collection vide aveclen(collection) == 0
estFalse
".Probablement un comportement attendu de l'opérateur & des tableaux de NumPy.
la source
Pour le premier exemple et base sur la doc de django
Il retournera toujours la deuxième liste, en effet une liste non vide est considérée comme une valeur True pour Python donc python renvoie la 'dernière' valeur True donc la deuxième liste
la source
Les opérations avec une liste Python opèrent sur la liste .
list1 and list2
vérifiera silist1
est vide, et retourneralist1
si c'est le cas, etlist2
si ce n'est pas le cas.list1 + list2
ajouteralist2
àlist1
, donc vous obtenez une nouvelle liste avec deslen(list1) + len(list2)
éléments.Les opérateurs qui n'ont de sens que lorsqu'ils sont appliqués par élément, tels que
&
lever aTypeError
, car les opérations par élément ne sont pas prises en charge sans boucler les éléments.Les tableaux Numpy prennent en charge les opérations élémentaires .
array1 & array2
calculera le bit à bit ou pour chaque élément correspondant dansarray1
etarray2
.array1 + array2
calculera la somme de chaque élément correspondant dansarray1
etarray2
.Cela ne fonctionne pas pour
and
etor
.array1 and array2
est essentiellement un raccourci pour le code suivant:Pour cela, vous avez besoin d'une bonne définition de
bool(array1)
. Pour les opérations globales comme celles utilisées sur les listes Python, la définition est quebool(list) == True
silist
n'est pas vide, etFalse
si elle est vide. Pour les opérations élément par élément de numpy, il y a une certaine homonymie s'il faut vérifier si un élément est évalué àTrue
ou si tous les éléments sont évalués àTrue
. Parce que les deux sont sans doute corrects, numpy ne devine pas et lève unValueError
whenbool()
est (indirectement) appelé sur un tableau.la source
Bonne question. Similaire à l'observation que vous avez sur les exemples 1 et 4 (ou devrais-je dire 1 & 4 :)) sur les opérateurs logiques au niveau du
and
bit&
, j'ai expérimenté sur l'sum
opérateur. Le numpysum
et le pysum
se comportent également différemment. Par exemple:Supposons que "mat" soit un tableau numpy 5x5 2d tel que:
Puis numpy.sum (mat) donne la somme totale de la matrice entière. Alors que la somme intégrée de Python telle que sum (mat) totalise le long de l'axe uniquement. Voir ci-dessous:
la source