J'ai vu plusieurs exemples de code comme celui-ci :
if not someobj:
#do something
Mais je me demande pourquoi ne pas le faire :
if someobj == None:
#do something
Y a-t-il une différence ? L'un a-t-il un avantage sur l'autre ?
J'ai vu plusieurs exemples de code comme celui-ci :
if not someobj:
#do something
Mais je me demande pourquoi ne pas le faire :
if someobj == None:
#do something
Y a-t-il une différence ? L'un a-t-il un avantage sur l'autre ?
Dans le premier test, Python essaie de convertir l'objet en un fichier bool
s'il ne l'est pas déjà. En gros, nous demandons à l'objet : as-tu un sens ou non ? Ceci est fait en utilisant l'algorithme suivant :
Si l'objet a un __nonzero__
méthode spéciale (tout comme les modules numériques), int
y float
), il appelle cette méthode. Elle doit soit retourner un bool
qui est ensuite directement utilisée, ou une valeur int
valeur qui est considérée comme False
si elle est égale à zéro.
Sinon, si l'objet a un __len__
méthode spéciale (comme le font les conteneurs intégrés, list
, dict
, set
, tuple
...), il appelle cette méthode, en considérant un conteneur False
s'il est vide (sa longueur est égale à zéro).
Sinon, l'objet est considéré comme True
à moins que ce ne soit None
auquel cas, il est considéré False
.
Dans le deuxième test, l'objet est comparé pour l'égalité à None
. Ici, nous demandons à l'objet : "Es-tu égal à cette autre valeur ?" Ceci est fait en utilisant l'algorithme suivant :
Si l'objet a un __eq__
elle est appelée, et la valeur de retour est alors convertie en une méthode bool
et utilisé pour déterminer le résultat de la if
.
Sinon, si l'objet a un __cmp__
il est appelé. Cette fonction doit retourner un int
indiquant l'ordre des deux objets ( -1
si self < other
, 0
si self == other
, +1
si self > other
).
Dans le cas contraire, les objets sont comparés pour vérifier leur identité (c'est-à-dire s'ils font référence au même objet, ce qui peut être vérifié par la fonction is
opérateur).
Il existe un autre test possible en utilisant le is
opérateur. On demanderait à l'objet : "Êtes-vous cet objet particulier ?"
D'une manière générale, je recommande d'utiliser le premier test avec des valeurs non numériques, d'utiliser le test d'égalité lorsque vous souhaitez comparer des objets de même nature (deux chaînes de caractères, deux nombres, ...) et de vérifier l'identité uniquement lorsque vous utilisez des valeurs sentinelles ( None
qui n'est pas initialisée pour un champ membre par exemple, ou lors de l'utilisation de la fonction getattr
ou le __getitem__
méthodes).
Pour résumer, nous avons :
>>> class A(object):
... def __repr__(self):
... return 'A()'
... def __nonzero__(self):
... return False
>>> class B(object):
... def __repr__(self):
... return 'B()'
... def __len__(self):
... return 0
>>> class C(object):
... def __repr__(self):
... return 'C()'
... def __cmp__(self, other):
... return 0
>>> class D(object):
... def __repr__(self):
... return 'D()'
... def __eq__(self, other):
... return True
>>> for obj in ['', (), [], {}, 0, 0., A(), B(), C(), D(), None]:
... print '%4s: bool(obj) -> %5s, obj == None -> %5s, obj is None -> %5s' % \
... (repr(obj), bool(obj), obj == None, obj is None)
'': bool(obj) -> False, obj == None -> False, obj is None -> False
(): bool(obj) -> False, obj == None -> False, obj is None -> False
[]: bool(obj) -> False, obj == None -> False, obj is None -> False
{}: bool(obj) -> False, obj == None -> False, obj is None -> False
0: bool(obj) -> False, obj == None -> False, obj is None -> False
0.0: bool(obj) -> False, obj == None -> False, obj is None -> False
A(): bool(obj) -> False, obj == None -> False, obj is None -> False
B(): bool(obj) -> False, obj == None -> False, obj is None -> False
C(): bool(obj) -> True, obj == None -> True, obj is None -> False
D(): bool(obj) -> True, obj == None -> True, obj is None -> False
None: bool(obj) -> False, obj == None -> True, obj is None -> True
Il s'agit en fait de deux mauvaises pratiques. Il fut un temps où l'on considérait qu'il était acceptable de traiter None et False comme similaires. Cependant, depuis Python 2.2, ce n'est plus la meilleure politique.
Premièrement, lorsque vous faites un if x
o if not x
Python doit convertir implicitement les tests de type x
en booléen. Les règles relatives à la bool
décrivent une série de choses qui sont fausses ; tout le reste est vrai. Si la valeur de x n'était pas proprement booléenne au départ, cette conversion implicite n'est pas vraiment la manière la plus claire de dire les choses.
Avant Python 2.2, il n'y avait pas de fonction bool, donc c'était encore moins clair.
Deuxièmement, vous ne devriez pas vraiment tester avec == None
. Vous devez utiliser is None
y is not None
.
Voir PEP 8, Guide de style pour le code Python .
- Comparisons to singletons like None should always be done with 'is' or 'is not', never the equality operators. Also, beware of writing "if x" when you really mean "if x is not None" -- e.g. when testing whether a variable or argument that defaults to None was set to some other value. The other value might have a type (such as a container) that could be false in a boolean context!
Combien de singletons y a-t-il ? Cinq : None
, True
, False
, NotImplemented
y Ellipsis
. Comme il est peu probable que vous utilisiez NotImplemented
o Ellipsis
et tu ne dirais jamais if x is True
(parce que simplement if x
est beaucoup plus clair), vous ne testerez jamais que les éléments suivants None
.
Parce que None
n'est pas la seule chose qui est considérée comme fausse.
if not False:
print "False is false."
if not 0:
print "0 is false."
if not []:
print "An empty list is false."
if not ():
print "An empty tuple is false."
if not {}:
print "An empty dict is false."
if not "":
print "An empty string is false."
False
, 0
, ()
, []
, {}
y ""
sont toutes différentes de None
Ainsi, vos deux extraits de code sont pas équivalent.
En outre, considérez ce qui suit :
>>> False == 0
True
>>> False == ()
False
if object:
est pas un contrôle d'égalité. 0
, ()
, []
, None
, {}
etc. sont toutes différentes les unes des autres, mais elles évaluer à Faux.
C'est la "magie" derrière les expressions de court-circuitage comme :
foo = bar and spam or eggs
ce qui est un raccourci pour :
if bar:
foo = spam
else:
foo = eggs
bien que vous devriez vraiment écrire :
foo = spam if bar else egg
Si vous demandez
if not spam:
print "Sorry. No SPAM."
le site __nonzéro__ méthode de spam est appelé. Extrait du manuel Python :
__nonzéro__ ( self ) Appelé pour implémenter le test de la valeur de vérité, et l'opération intégrée bool() ; doit retourner Faux ou Vrai, ou leurs équivalents entiers 0 ou 1. Lorsque cette méthode n'est pas définie, __len__() est appelée, si elle est définie (voir ci-dessous). Si une classe ne définit ni __len__() ni __nonzero__(), toutes ses instances sont considérées comme vraies.
Si vous demandez
if spam == None:
print "Sorry. No SPAM here either."
le site __eq__ méthode de spam est appelé avec l'argument Aucun .
Pour plus d'informations sur les possibilités de personnalisation, consultez la documentation Python à l'adresse suivante https://docs.python.org/reference/datamodel.html#basic-customization
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.