Je reçois une erreur dans le conditionnel IF. Qu'est-ce que je fais mal?
La raison pour laquelle vous obtenez un SyntaxError
est qu'il n'y a pas d' &&
opérateur en Python. De même ||
et ne!
sont pas des opérateurs Python valides .
Certains des opérateurs que vous connaissez peut-être dans d'autres langues ont un nom différent en Python. Les opérateurs logiques &&
et ||
sont en fait appelés and
et or
. De même, l'opérateur de négation logique !
est appelé not
.
Vous pouvez donc simplement écrire:
if len(a) % 2 == 0 and len(b) % 2 == 0:
ou même:
if not (len(a) % 2 or len(b) % 2):
Quelques informations supplémentaires (qui pourraient être utiles):
J'ai résumé l'opérateur "équivalents" dans ce tableau:
+------------------------------+---------------------+
| Operator (other languages) | Operator (Python) |
+==============================+=====================+
| && | and |
+------------------------------+---------------------+
| || | or |
+------------------------------+---------------------+
| ! | not |
+------------------------------+---------------------+
Voir aussi la documentation Python: 6.11. Opérations booléennes .
Outre les opérateurs logiques, Python possède également des opérateurs binaires / binaires:
+--------------------+--------------------+
| Logical operator | Bitwise operator |
+====================+====================+
| and | & |
+--------------------+--------------------+
| or | | |
+--------------------+--------------------+
Il n'y a pas de négation au niveau du bit en Python (juste l'opérateur inverse au niveau du bit ~
- mais ce n'est pas équivalent à not
).
Voir aussi 6.6. Opérations arithmétiques unaires et au niveau du bit / binaire et 6.7. Opérations arithmétiques binaires .
Les opérateurs logiques (comme dans beaucoup d'autres langues) ont l'avantage d'être court-circuités. Cela signifie que si le premier opérande définit déjà le résultat, le deuxième opérateur n'est pas évalué du tout.
Pour le montrer, j'utilise une fonction qui prend simplement une valeur, l'imprime et la renvoie à nouveau. C'est pratique pour voir ce qui est réellement évalué en raison des instructions d'impression:
>>> def print_and_return(value):
... print(value)
... return value
>>> res = print_and_return(False) and print_and_return(True)
False
Comme vous pouvez le voir, une seule instruction print est exécutée, donc Python n'a même pas regardé l'opérande approprié.
Ce n'est pas le cas pour les opérateurs binaires. Ceux-ci évaluent toujours les deux opérandes:
>>> res = print_and_return(False) & print_and_return(True);
False
True
Mais si le premier opérande ne suffit pas, alors, bien sûr, le deuxième opérateur est évalué:
>>> res = print_and_return(True) and print_and_return(False);
True
False
Pour résumer ceci, voici un autre tableau:
+-----------------+-------------------------+
| Expression | Right side evaluated? |
+=================+=========================+
| `True` and ... | Yes |
+-----------------+-------------------------+
| `False` and ... | No |
+-----------------+-------------------------+
| `True` or ... | No |
+-----------------+-------------------------+
| `False` or ... | Yes |
+-----------------+-------------------------+
Les True
et False
représentent ce qui bool(left-hand-side)
retourne, ils n'ont pas à être True
ou False
, ils ont juste besoin de revenir True
ou False
quand bool
est appelé sur eux (1).
Ainsi, dans le pseudo-code (!) and
, Les or
fonctions et fonctionnent comme suit:
def and(expr1, expr2):
left = evaluate(expr1)
if bool(left):
return evaluate(expr2)
else:
return left
def or(expr1, expr2):
left = evaluate(expr1)
if bool(left):
return left
else:
return evaluate(expr2)
Notez qu'il s'agit de pseudo-code et non de code Python. En Python, vous ne pouvez pas créer de fonctions appelées and
ou or
parce que ce sont des mots clés. De plus, vous ne devez jamais utiliser "évaluer" ou if bool(...)
.
Personnalisation du comportement de vos propres classes
Cet bool
appel implicite peut être utilisé pour personnaliser le comportement de vos classes avec and
, or
et not
.
Pour montrer comment cela peut être personnalisé, j'utilise cette classe qui, encore print
une fois, permet de suivre ce qui se passe:
class Test(object):
def __init__(self, value):
self.value = value
def __bool__(self):
print('__bool__ called on {!r}'.format(self))
return bool(self.value)
__nonzero__ = __bool__ # Python 2 compatibility
def __repr__(self):
return "{self.__class__.__name__}({self.value})".format(self=self)
Voyons donc ce qui se passe avec cette classe en combinaison avec ces opérateurs:
>>> if Test(True) and Test(False):
... pass
__bool__ called on Test(True)
__bool__ called on Test(False)
>>> if Test(False) or Test(False):
... pass
__bool__ called on Test(False)
__bool__ called on Test(False)
>>> if not Test(True):
... pass
__bool__ called on Test(True)
Si vous n'avez pas de __bool__
méthode, Python vérifie également si l'objet a une __len__
méthode et s'il renvoie une valeur supérieure à zéro. Cela peut être utile de savoir si vous créez un conteneur de séquence.
Voir aussi 4.1. Test de valeur de vérité .
Tableaux et sous-classes NumPy
Probablement un peu au-delà de la portée de la question d'origine, mais dans le cas où vous avez affaire à des tableaux ou sous-classes NumPy (comme Pandas Series ou DataFrames), l' bool
appel implicite augmentera le redouté ValueError
:
>>> import numpy as np
>>> arr = np.array([1,2,3])
>>> bool(arr)
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
>>> arr and arr
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
>>> import pandas as pd
>>> s = pd.Series([1,2,3])
>>> bool(s)
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
>>> s and s
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
Dans ces cas, vous pouvez utiliser la logique et la fonction de NumPy qui effectue un élément and
(ou or
):
>>> np.logical_and(np.array([False,False,True,True]), np.array([True, False, True, False]))
array([False, False, True, False])
>>> np.logical_or(np.array([False,False,True,True]), np.array([True, False, True, False]))
array([ True, False, True, True])
Si vous traitez uniquement avec des tableaux booléens, vous pouvez également utiliser les opérateurs binaires avec NumPy, ceux-ci effectuent des comparaisons par élément (mais aussi binaire):
>>> np.array([False,False,True,True]) & np.array([True, False, True, False])
array([False, False, True, False])
>>> np.array([False,False,True,True]) | np.array([True, False, True, False])
array([ True, False, True, True])
(1)
Que l' bool
appel sur les opérandes doit retourner True
ou False
n'est pas complètement correct. C'est juste le premier opérande qui doit retourner un booléen dans sa __bool__
méthode:
class Test(object):
def __init__(self, value):
self.value = value
def __bool__(self):
return self.value
__nonzero__ = __bool__ # Python 2 compatibility
def __repr__(self):
return "{self.__class__.__name__}({self.value})".format(self=self)
>>> x = Test(10) and Test(10)
TypeError: __bool__ should return bool, returned int
>>> x1 = Test(True) and Test(10)
>>> x2 = Test(False) and Test(10)
C'est parce and
que retourne en fait le premier opérande si le premier opérande évalue à False
et s'il évalue à True
alors il retourne le deuxième opérande:
>>> x1
Test(10)
>>> x2
Test(False)
De même pour or
mais juste l'inverse:
>>> Test(True) or Test(10)
Test(True)
>>> Test(False) or Test(10)
Test(10)
Toutefois, si vous les utilisez dans une if
instruction, le résultat if
invoquera également implicitement bool
le résultat. Ces points plus fins peuvent donc ne pas être pertinents pour vous.