web-dev-qa-db-fra.com

Est-il sûr de se fier à l'ordre d'évaluation des conditions dans les instructions if?

Est-ce une mauvaise pratique d'utiliser le format suivant lorsque my_var peut être Aucun?

if my_var and 'something' in my_var:
    #do something

Le problème est que 'something' in my_var lancera une TypeError si my_var est None.

Ou devrais-je utiliser:

if my_var:
    if 'something' in my_var:
        #do something

ou

try:
    if 'something' in my_var:
        #do something
except TypeError:
    pass

Pour reformuler la question, laquelle des méthodes ci-dessus est la meilleure pratique dans Python (le cas échéant)?

Les alternatives sont les bienvenues!

65
tgray

Il est sûr de dépendre de l'ordre des conditions ( référence Python ici ), en particulier en raison du problème que vous signalez - il est très utile de pouvoir court-circuiter l'évaluation qui pourrait causer des problèmes dans une chaîne de conditionnels.

Ce type de code apparaît dans la plupart des langues:

IF exists(variable) AND variable.doSomething()
    THEN ...
83
Daniel Lew

Oui c'est sûr, c'est explicitement et très clairement défini dans la référence du langage:

L'expression x and y évalue d'abord x; si x est false, sa valeur est retournée; sinon, y est évalué et la valeur résultante est renvoyée.

L'expression x or y évalue d'abord x; si x est vrai, sa valeur est retournée; sinon, y est évalué et la valeur résultante est renvoyée.

31
vartec

Je suis peut-être un peu pédant ici, mais je dirais que la meilleure réponse est

if my_var is not None and 'something' in my_var:
    #do something

La différence étant la vérification explicite de None, plutôt que la conversion implicite de my_var à True ou False.

Bien que je sois sûr que dans votre cas, la distinction n'est pas importante, dans le cas plus général, il serait tout à fait possible que la variable ne soit pas None mais qu'elle soit toujours évaluée à False, par exemple une valeur entière de 0 ou une liste vide.

Donc, contrairement à la plupart des affirmations des autres affiches selon lesquelles c'est sûr, je dirais que c'est sûr tant que vous êtes explicite. Si vous n'êtes pas convaincu, pensez à cette classe très artificielle:

class Contrived(object):
    def __contains__(self, s):
        return True
    def __nonzero__(self):
        return False

my_var = Contrived()
if 'something' in my_var:
    print "Yes the condition is true"
if my_var and 'something' in my_var:
    print "But this statement won't get reached."
if my_var is not None and 'something' in my_var:
    print "Whereas this one will."

Oui, je sais que ce n'est pas un exemple réaliste, mais des variations se produisent dans le code réel, en particulier lorsque None est utilisé pour indiquer un argument de fonction par défaut.

2
Scott Griffiths

C'est parfaitement sûr et je le fais tout le temps.

1
FogleBird

J'irais avec le try/except, mais cela dépend de ce que vous savez sur la variable.

Si vous vous attendez à ce que la variable existe la plupart du temps, alors un essai/except est moins d'opérations. Si vous vous attendez à ce que la variable soit None la plupart du temps, alors une instruction IF sera moins d'opérations.

1
Jason Coon

Ce n'est pas aussi simple. En tant que mec C #, j'ai l'habitude de faire quelque chose comme:

if(x != null && ! string.isnullorempty(x.Name))
{
   //do something
}

Ce qui précède fonctionne très bien et est évalué comme prévu. Cependant, dans VB.Net, les résultats suivants produiraient un résultat auquel vous ne vous attendiez pas:

If Not x Is Nothing **And** Not String.IsNullOrEmpty(x.Name) Then

   'do something

End If

Ce qui précède générera une exception. La syntaxe correcte doit être

If Not x Is Nothing **AndAlso** Not String.IsNullOrEmpty(x.Name) Then

   'do something

End If

Notez la différence très subtile. Cela m'a dérouté pendant environ 10 minutes (beaucoup trop long) et c'est pourquoi les mecs C # (et autres) doivent être très prudents lors du codage dans d'autres langages.

1
Hans