J'ai vu plusieurs exemples de code comme celui-ci:
if not someobj:
#do something
Mais je me demande pourquoi ne pas faire:
if someobj == None:
#do something
Y a-t-il une différence? L'un a-t-il un avantage sur l'autre?
X != None?
J'ai vu plusieurs exemples de code comme celui-ci:
if not someobj:
#do something
Mais je me demande pourquoi ne pas faire:
if someobj == None:
#do something
Y a-t-il une différence? L'un a-t-il un avantage sur l'autre?
X != None?
Réponses:
Dans le premier test, Python essaie de convertir l'objet en une boolvaleur s'il n'en est pas déjà une. En gros, nous demandons à l'objet: êtes-vous significatif ou non? Cela se fait à l'aide de l'algorithme suivant:
Si l'objet a une __nonzero__méthode spéciale (comme le font les intégrés numériques, intet float), il appelle cette méthode. Il doit soit renvoyer une boolvaleur qui est alors directement utilisée, soit une intvaleur considérée Falsesi égale à zéro.
Dans le cas contraire, si l'objet a une __len__méthode spéciale (comme les conteneurs Encastrements, list, dict, set, tuple, ...), il appelle cette méthode, compte tenu d' un récipient Falsesi elle est vide (longueur est égale à zéro).
Sinon, l'objet est considéré à Truemoins que ce ne soit le Nonecas auquel cas, il est considéré False.
Dans le deuxième test, l’égalité de l’objet est comparée à None. Ici, nous demandons à l'objet: "Êtes-vous égal à cette autre valeur?" Cela se fait à l'aide de l'algorithme suivant:
Si l'objet a une __eq__méthode, il est appelé et la valeur de retour est ensuite convertie en boolvaleur et utilisée pour déterminer le résultat du if.
Sinon, si l'objet a une __cmp__méthode, il est appelé. Cette fonction doit renvoyer un intindiquant l'ordre des deux objets ( -1si self < other, 0si self == other, +1si self > other).
Sinon, les objets sont comparés pour l'identité (c'est-à-dire qu'ils font référence au même objet, comme cela peut être testé par l' isopérateur).
Il existe un autre test possible en utilisant l' isopérateur. Nous demanderions à l'objet: "Êtes-vous cet objet particulier?"
De manière générale, je recommanderais 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, deux nombres, ...) et de vérifier l'identité uniquement lorsque en utilisant des valeurs sentinelles ( Nonec'est-à-dire non initialisé pour un champ membre par exemple, ou lors de l'utilisation getattrdes __getitem__méthodes ou ).
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
Ce sont en fait deux mauvaises pratiques. Il était une fois, il était considéré comme acceptable de traiter avec désinvolture None et False comme similaires. Cependant, depuis Python 2.2, ce n'est pas la meilleure politique.
Premièrement, lorsque vous effectuez un test if xou un if not xtype de test, Python doit implicitement se convertir xen booléen. Les règles de la boolfonction décrivent une série de choses qui sont fausses; tout le reste est vrai. Si la valeur de x n'était pas correctement booléenne au départ, cette conversion implicite n'est pas vraiment la façon la plus claire de dire les choses.
Avant Python 2.2, il n'y avait pas de fonction booléenne, donc c'était encore moins clair.
Deuxièmement, vous ne devriez pas vraiment tester avec == None. Vous devez utiliser is Noneet 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 y a-t-il de singletons? Cinq: None, True, False, NotImplementedet Ellipsis. Comme il est peu probable que vous utilisiez NotImplementedou Ellipsis, et que vous ne diriez jamaisif x is True (parce que if xc'est beaucoup plus clair), vous ne testerez jamais None.
Parce que ce Nonen'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, (), [], {}Et ""sont toutes différentes None, de sorte que vos deux extraits de code sont pas équivalents.
De plus, considérez ce qui suit:
>>> False == 0
True
>>> False == ()
False
if object:n'est pas un contrôle d'égalité. 0, (), [], None, {}, Etc. sont tous différents les uns des autres, mais ils ont tous évaluent à Faux.
C'est la "magie" derrière les expressions de court-circuit comme:
foo = bar and spam or eggs
qui est un raccourci pour:
if bar:
foo = spam
else:
foo = eggs
bien que vous devriez vraiment écrire:
foo = spam if bar else egg
PEP 8 - Guide de style pour le code Python recommande d'utiliser is ou non si vous testez None-ness
- Comparisons to singletons like None should always be done with 'is' or 'is not', never the equality operators.
D'un autre côté, si vous testez plus de None-ness, vous devez utiliser l'opérateur booléen.
Si vous demandez
if not spam:
print "Sorry. No SPAM."
la méthode __nonzero__ de spam est appelée. À partir du manuel Python:
__nonzero__ ( self ) Appelé pour implémenter le test de la valeur de vérité et l'opération intégrée bool (); doit renvoyer False ou True, 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."
la méthode __eq__ de spam est appelée avec l'argument None .
Pour plus d'informations sur les possibilités de personnalisation, consultez la documentation Python à https://docs.python.org/reference/datamodel.html#basic-customization
Ces deux comparaisons servent des objectifs différents. Le premier vérifie la valeur booléenne de quelque chose, le second vérifie l'identité avec la valeur None.
La réponse est "ça dépend".
J'utilise le premier exemple si je considère 0, "", [] et False (liste non exhaustive) comme équivalents à None dans ce contexte.
Personnellement, j'ai choisi une approche cohérente à travers les langages: je ne fais if (var)(ou équivalent) que si var est déclaré booléen (ou défini comme tel, en C nous n'avons pas de type spécifique). Je préfixe même ces variables avec un b(donc ce serait en bVarfait) pour être sûr que je n'utiliserai pas accidentellement un autre type ici.
Je n'aime pas vraiment le cast implicite en booléen, encore moins quand il y a de nombreuses règles complexes.
Bien sûr, les gens ne seront pas d'accord. Certains vont plus loin, je vois if (bVar == true)dans le code Java à mon travail (trop redondant à mon goût!), D'autres aiment trop la syntaxe compacte, aller while (line = getNextLine())(trop ambigu pour moi).