Réponses:
La déclaration
if A:
appellera A.__nonzero__()(voir la documentation des noms de méthodes spéciales ) et utilisera la valeur de retour de cette fonction. Voici le résumé:
object.__nonzero__(self)Appelé à implémenter le test de valeur de vérité et l'opération intégrée
bool(); doit renvoyerFalseouTrue, ou leurs équivalents entiers0ou1. Lorsque cette méthode n'est pas définie,__len__()est appelée, si elle est définie, et l'objet est considéré comme vrai si son résultat est différent de zéro. Si une classe ne définit ni__len__()ni__nonzero__(), toutes ses instances sont considérées comme vraies.
D'autre part,
if A is not None:
compare uniquement la référence Aavec Nonepour voir si elle est la même ou non.
if object(): passest d'environ 0,130 usec par boucle, tandis que d' if object() is not None: passenviron 0,135 usec. Quoi qu'il en soit, vous ne devriez pas utiliser les performances pour choisir entre ces deux, mais plutôt regarder les différences dans leur fonctionnement, car elles ne sont pas équivalentes .
if A is not Nonesemble être plus lent car il s'agit d'une comparaison et doit charger le singleton intégré Nonecomme étape intermédiaire avec laquelle comparer A(jetez un œil au dis.dis()). Corrigez-moi si je me trompe mais if A:semble être plus efficace, dès que vous voulez vraiment tester la valeur de vérité et non l' Noneidentité.
python -m timeit -s"a=0" "if a: pass" "else: pass"est plus rapide que python -m timeit -s"a=0" "if a is None: pass" "else: pass"mais python -m timeit -s"a=1" "if a: pass" "else: pass"est plus lent. Peut-être dépendant de la plate-forme, voyez si vous obtenez les mêmes résultats
is Nonetest était en effet le plus lent pour moi. En pypy, ils mesuraient tous exactement la même chose :)
Comme écrit dans PEP8 :
Les comparaisons avec des singletons comme None doivent toujours être effectuées avec 'is' ou 'is not', jamais avec les opérateurs d'égalité .
Aussi, méfiez - vous d'écrire «si x» lorsque vous voulez vraiment dire «si x n'est pas None» - par exemple, lorsque vous testez si une variable ou un argument par défaut None a été défini sur une autre valeur. L'autre valeur peut avoir un type (tel qu'un conteneur) qui pourrait être faux dans un contexte booléen!
None, mais juste par une vérification de la valeur de vérité. Dans ce cas, cela if A:semble plus efficace (prenez a dis.dis(), il y a les étapes supplémentaires de chargement du builtin Noneet de comparaison, avec if A is not None:, alors qu'il n'y en a qu'un jump_ifdans l'autre cas).
if x: #x is treated True except for all empty data types [],{},(),'',0 False, and None
donc ce n'est pas la même chose que
if x is not None # which works only on None
De nombreuses fonctions renvoient None s'il n'y a pas de résultats appropriés. Par exemple, la .first()méthode d' une requête SQLAlchemy renvoie None s'il n'y avait aucune ligne dans le résultat. Supposons que vous sélectionniez une valeur susceptible de renvoyer 0 et que vous ayez besoin de savoir si elle est réellement 0 ou si la requête n'a donné aucun résultat.
Un idiome courant est de donner à l'argument facultatif d'une fonction ou d'une méthode la valeur par défaut None, puis de tester cette valeur étant None pour voir si elle a été spécifiée. Par exemple:
def spam(eggs=None):
if eggs is None:
eggs = retrievefromconfigfile()
comparez cela à:
def spam(eggs=None):
if not eggs:
eggs = retrievefromconfigfile()
Dans ce dernier, que se passe-t-il si vous appelez spam(0)ou spam([])? La fonction détecte (à tort) que vous n'avez pas transmis de valeur pour eggset calcule une valeur par défaut pour vous. Ce n'est probablement pas ce que vous voulez.
Ou imaginez une méthode comme "retourner la liste des transactions pour un compte donné". Si le compte n'existe pas, il peut renvoyer None. Ceci est différent de renvoyer une liste vide (ce qui signifierait que "ce compte existe mais n'a pas enregistré de transactions).
Enfin, revenons à la base de données. Il y a une grande différence entre NULL et une chaîne vide. Une chaîne vide indique généralement "il y a une valeur ici, et cette valeur n'est rien du tout". NULL indique que "cette valeur n'a pas été saisie."
Dans chacun de ces cas, vous voudriez utiliser if A is None. Vous recherchez une valeur spécifique - Aucune - pas seulement "toute valeur qui se trouve être convertie en False".
Ils font des choses très différentes .
Les contrôles ci - dessous si A a quelque chose à l' exception des valeurs False, [], None, ''et 0. Il vérifie la valeur de A.
if A:
Ce qui suit vérifie si A est un objet différent de None. Il vérifie et compare la référence (adresse mémoire) de A et None.
if A is not None:
MISE À JOUR: Explication supplémentaire
Souvent, les deux semblent faire la même chose, donc beaucoup de gens les utilisent de manière interchangeable - c'est une très mauvaise idée. La raison pour laquelle les deux donnent les mêmes résultats est souvent par pure coïncidence due à des optimisations de l'interpréteur / compilateur comme l' internement ou autre chose.
Avec ces optimisations à l'esprit, les entiers et les chaînes de même valeur finissent par utiliser le même espace mémoire. Cela explique probablement pourquoi deux chaînes distinctes agissent comme si elles étaient identiques.
> a = 'test'
> b = 'test'
> a is b
True
> a == b
True
Cependant, d'autres choses ne se comportent pas de la même manière.
> a = []
> b = []
> a is b
False
> a == b
True
Les deux listes ont clairement leur propre mémoire. Étonnamment, les tuples se comportent comme des chaînes.
> a = ()
> b = ()
> a is b
True
> a == b
True
C'est probablement parce que les tuples sont garantis de ne pas changer, il est donc logique de réutiliser la même mémoire.
En bout de ligne, vous ne pouvez pas vous fier aux coïncidences . Ce n'est pas parce que ça caque comme un canard que c'est un canard. Utilisez iset en ==fonction de ce que vous voulez vraiment vérifier. Ces choses peuvent être difficiles à déboguer car se islit comme de la prose que nous passons souvent en revue.
Noneest un singleton, ce n'est pas un détail d'implémentation (contrairement à int ou string interning). Je ne suis pas sûr de comprendre ce que tu veux dire.
Nonese comporte différemment intou en strraison de l'internement. Mon point est que iset ==vérifie des choses différentes; vérifie d'abord une adresse mémoire, le second vérifie le contenu des adresses mémoire.
if A: se révélera faux si A vaut 0, Faux, chaîne vide, liste vide ou Aucun, ce qui peut conduire à des résultats indésirables.
La plupart des guides que j'ai vus suggèrent que vous devriez utiliser
si un:
sauf si vous avez une raison d'être plus précis.
Il y a quelques légères différences. Il existe des valeurs autres que None qui renvoient False, par exemple des listes vides ou 0, alors réfléchissez à ce que vous testez réellement.
None est une valeur spéciale en Python qui désigne généralement une variable non initialisée. Pour tester si A n'a pas cette valeur particulière, utilisez:
if A is not None
Les valeurs Falsey sont une classe spéciale d'objets en Python (par exemple, false, []). Pour tester si A est faux, utilisez:
if not A
Ainsi, les deux expressions ne sont pas les mêmes et vous feriez mieux de ne pas les traiter comme des synonymes.
PS None est également faux, donc la première expression implique la seconde. Mais la seconde couvre d'autres valeurs fausses en plus de None. Maintenant ... si vous pouvez être sûr que vous ne pouvez pas avoir d'autres valeurs fausses en plus de None dans A, alors vous pouvez remplacer la première expression par la seconde.
Ça dépend du contexte.
J'utilise if A:quand je m'attends Aà être une sorte de collection, et je veux seulement exécuter le bloc si la collection n'est pas vide. Cela permet à l'appelant de passer n'importe quelle collection bien comportée, vide ou non, et de lui faire faire ce que j'attends. Il permet également Noneet Falsede supprimer l'exécution du bloc, ce qui est parfois pratique pour appeler du code.
OTOH, si je m'attends Aà être un objet complètement arbitraire mais qu'il aurait pu être défini par défaut None, alors je l' utilise toujoursif A is not None , car le code d'appel aurait pu délibérément passer une référence à une collection vide, une chaîne vide ou un type numérique de valeur 0, ou booléen False, ou une instance de classe qui se trouve être fausse dans un contexte booléen.
Et d'un autre côté, si je m'attends Aà être quelque chose de plus spécifique (par exemple, une instance d'une classe dont je vais appeler des méthodes), mais cela aurait pu être défini par défaut None, et je considère la conversion booléenne par défaut comme un propriété de la classe Cela ne me dérange pas d'appliquer à toutes les sous-classes, alors je vais simplement utiliser if A:pour sauver mes doigts le terrible fardeau de taper 12 caractères supplémentaires.
J'ai créé un fichier appelé test.pyet l' ai exécuté sur l'interpréteur. Vous pouvez changer ce que vous voulez, pour vérifier avec certitude comment les choses se passent dans les coulisses.
import dis
def func1():
matchesIterator = None
if matchesIterator:
print( "On if." );
def func2():
matchesIterator = None
if matchesIterator is not None:
print( "On if." );
print( "\nFunction 1" );
dis.dis(func1)
print( "\nFunction 2" );
dis.dis(func2)
C'est la différence de l'assembleur:

La source:
>>> import importlib
>>> reload( test )
Function 1
6 0 LOAD_CONST 0 (None)
3 STORE_FAST 0 (matchesIterator)
8 6 LOAD_FAST 0 (matchesIterator)
9 POP_JUMP_IF_FALSE 20
10 12 LOAD_CONST 1 ('On if.')
15 PRINT_ITEM
16 PRINT_NEWLINE
17 JUMP_FORWARD 0 (to 20)
>> 20 LOAD_CONST 0 (None)
23 RETURN_VALUE
Function 2
14 0 LOAD_CONST 0 (None)
3 STORE_FAST 0 (matchesIterator)
16 6 LOAD_FAST 0 (matchesIterator)
9 LOAD_CONST 0 (None)
12 COMPARE_OP 9 (is not)
15 POP_JUMP_IF_FALSE 26
18 18 LOAD_CONST 1 ('On if.')
21 PRINT_ITEM
22 PRINT_NEWLINE
23 JUMP_FORWARD 0 (to 26)
>> 26 LOAD_CONST 0 (None)
29 RETURN_VALUE
<module 'test' from 'test.py'>
python> = 2,6,
si nous écrivons comme
if A:
générera un avertissement comme,
FutureWarning: Le comportement de cette méthode changera dans les versions futures. Utilisez plutôt le test spécifique «len (elem)» ou «elem is not None».
Nous pouvons donc utiliser
if A is not None:
A is not Noneest donc plus rapide car il y a beaucoup moins de travail à faire