web-dev-qa-db-fra.com

Python évalue-t-il les conditions de if paresseusement?

Par exemple, si j'ai la déclaration suivante:

if( foo1 or foo2)
    ...
    ...

si foo1 est vrai, python vérifiera-t-il l'état de foo2?

56
ogama8

Oui, Python évalue les conditions booléennes paresseusement.

Les les docs disent ,

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

L'expression x ou 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.

75
unutbu

andor est paresseux

&| n'est pas paresseux

24
Eric Wang

La paresse de Python peut être prouvée par le code suivant:

def foo():
    print('foo')
    return False

def bar():
    print('bar')
    return False

foo() and bar()         #Only 'foo' is printed

D'autre part,

foo() or bar()

entraînerait à la fois "foo" et "bar" à imprimer.

10
Erik Veloso

Ce n'est pas une évaluation techniquement paresseuse, ce sont des expressions booléennes de court-circuit.

L'évaluation paresseuse a une connotation quelque peu différente. Par exemple, une véritable évaluation paresseuse permettrait probablement

def foo(arg) :
    print "Couldn't care less"

foo([][0])

Mais Python ne le fait pas.

Python est également agréable en ce qu'il "fait écho" à ses arguments booléens. Par exemple, une condition ou renvoie soit son premier argument "véridique" soit le dernier argument (si tous les arguments sont "falsey"). Une condition et fait l'inverse.

Donc, "l'argument d'écho" booléens signifie

2 et [] et 1

évalue à [], et

[] ou 1 ou 2

évalue à 1

5
Pete Cacioppi

Oui, Python évalue paresseusement, donc foo2 ne sera pas vérifié.

Je l'utilise tout le temps pour récupérer des éléments à partir d'objets de type dictionnaire si je ne sais pas si la clé existe:

if 'key' in mydict and mydict['key'] == 'heyyo!':
    do_stuff()

Voir la réponse de @ unutbu pour une explication plus complète.

2
jdotjdot

C'est vraiment la partie or qui est court-circuitée:

>>> 1 or 1/0  #also 0 and 1/0
1
>>> 0 or 1/0  #also 1 and 1/0

Traceback (most recent call last):
  File "<pyshell#1240>", line 1, in <module>
    0 or 1/0
ZeroDivisionError: integer division or modulo by zero
1
dansalmo

Une courte démonstration serait de comparer la différence de temps entre

all(xrange(1,1000000000))

et

any(xrange(1,1000000000))

Le all () doit vérifier chaque valeur unique, tandis que le any () peut abandonner une fois que le premier True a été trouvé. Le xrange, étant un générateur, renonce donc également à générer des choses dès que l'évaluateur a terminé. Pour cette raison, le tout consommera de grandes quantités de RAM et prendra des âges, tandis que le tout n'utilisera que quelques octets et reviendra instantanément.

1
J.J