Ответ 1
В любом случае expr1 == expr2
оценивается false
в if
, второй не будет оцениваться.
Есть ли разница в эффективности между использованием и в выражении if и использованием нескольких операторов if? Другими словами, это что-то вроде
if expr1 == expr2 and expr3==expr4:
dostuff()
отличается от точки эффективности, тогда:
if expr1 == expr2:
if expr3 == expr4:
dostuff()
Мое очень основное тестирование не раскрывает разницы, но кто-то с большим количеством знаний (или, по крайней мере, более тщательное тестирование) имеет окончательный ответ?
В любом случае expr1 == expr2
оценивается false
в if
, второй не будет оцениваться.
Этого недостаточно, чтобы повлиять на ваше решение. ИМО, решение здесь должно быть сделано исключительно с точки зрения читаемости. Я думаю, что первое, как правило, более стандартное, но есть ситуации, когда второй может быть более ясным. Выберите метод, который наилучшим образом использует ваше намерение.
Любые различия в скорости между использованием and
и вложенными ifs будут минимальными. Вы лаяете неправильное дерево. Рассмотрим это дерево:
if oftenTrueCondition and rarelyTrueCondition:
по сравнению с
if rarelyTrueCondition and oftenTrueCondition:
Итак, если первое условие не должно оцениваться первым (это защита, чтобы остановить следующее выражение от сбоя или сделать что-то глупое/дорогое), подумайте об изменении порядка оценки.
Если вы сомневаетесь, вы можете проверить, что делает python для компиляции ваших операторов, используя этот модуль:
>>> import dis
>>> def test1():
... if expr1 == expr2 and expr3==expr4:
... dostuff()
...
>>> def test2():
... if expr1 == expr2:
... if expr3 == expr4:
... dostuff()
...
>>> dis.dis(test1)
2 0 LOAD_GLOBAL 0 (expr1)
3 LOAD_GLOBAL 1 (expr2)
6 COMPARE_OP 2 (==)
9 JUMP_IF_FALSE 24 (to 36)
12 POP_TOP
13 LOAD_GLOBAL 2 (expr3)
16 LOAD_GLOBAL 3 (expr4)
19 COMPARE_OP 2 (==)
22 JUMP_IF_FALSE 11 (to 36)
25 POP_TOP
3 26 LOAD_GLOBAL 4 (dostuff)
29 CALL_FUNCTION 0
32 POP_TOP
33 JUMP_FORWARD 1 (to 37)
>> 36 POP_TOP
>> 37 LOAD_CONST 0 (None)
40 RETURN_VALUE
>>> dis.dis(test2)
2 0 LOAD_GLOBAL 0 (expr1)
3 LOAD_GLOBAL 1 (expr2)
6 COMPARE_OP 2 (==)
9 JUMP_IF_FALSE 28 (to 40)
12 POP_TOP
3 13 LOAD_GLOBAL 2 (expr3)
16 LOAD_GLOBAL 3 (expr4)
19 COMPARE_OP 2 (==)
22 JUMP_IF_FALSE 11 (to 36)
25 POP_TOP
4 26 LOAD_GLOBAL 4 (dostuff)
29 CALL_FUNCTION 0
32 POP_TOP
33 JUMP_ABSOLUTE 41
>> 36 POP_TOP
37 JUMP_FORWARD 1 (to 41)
>> 40 POP_TOP
>> 41 LOAD_CONST 0 (None)
44 RETURN_VALUE
Итак, как вы можете видеть, на уровне байт-кода python оба оператора одинаковы - даже если вы используете сингл, если в первом выражении, он будет делать JUMP_IF_FALSE после первого сравнения.
Первый (один if
с and
) быстрее: -)
Я попробовал это с помощью timeit
. Вот результаты:
Variant 1: 9.82836714316
Variant 2: 9.83886494559
Variant 1 (True): 9.66493159804
Variant 2 (True): 10.0392633241
Для последних двух первое сравнение - True
, поэтому второе пропускается. Интересные результаты.
import timeit
print "Variant 1: %s" % timeit.timeit("""
for i in xrange(1000):
if i == 2*i and i == 3*i:
pass
""",
number = 1000)
print "Variant 2: %s" % timeit.timeit("""
for i in xrange(1000):
if i == 2*i:
if i == 3*i:
pass
""",
number = 1000)
print "Variant 1 (True): %s" % timeit.timeit("""
for i in xrange(1000):
if i == i and i == 3*i:
pass
""",
number = 1000)
print "Variant 2 (True): %s" % timeit.timeit("""
for i in xrange(1000):
if i == i:
if i == 3*i:
pass
""",
number = 1000)