Skip to content

Instantly share code, notes, and snippets.

@alexandre
Created March 10, 2015 23:06
Show Gist options
  • Select an option

  • Save alexandre/874cdfd609d9aee2bc3d to your computer and use it in GitHub Desktop.

Select an option

Save alexandre/874cdfd609d9aee2bc3d to your computer and use it in GitHub Desktop.
boolean or range?
>>> import dis
>>>
>>> def foo_with_bool(foo): return foo < 1 or foo > 12
...
>>> def foo_with_range(foo): return foo in range(1,13)
...
>>> dis.dis(foo_with_bool)
1 0 LOAD_FAST 0 (foo)
3 LOAD_CONST 1 (1)
6 COMPARE_OP 0 (<)
9 JUMP_IF_TRUE_OR_POP 21
12 LOAD_FAST 0 (foo)
15 LOAD_CONST 2 (12)
18 COMPARE_OP 4 (>)
>> 21 RETURN_VALUE
>>> dis.dis(foo_with_range)
1 0 LOAD_FAST 0 (foo)
3 LOAD_GLOBAL 0 (range)
6 LOAD_CONST 1 (1)
9 LOAD_CONST 2 (13)
12 CALL_FUNCTION 2 (2 positional, 0 keyword pair)
15 COMPARE_OP 6 (in)
18 RETURN_VALUE
>>>
@henriquebastos
Copy link

Maneiro o exercício.

Experimentando com o seu código observei que o bool é mais rápido como esperado. Mais ainda quando ocorre curto circuito que economiza a validação da expressão à direita do or.

>>>timeit.timeit('foo_with_bool(2)', 'def foo_with_bool(foo): return foo < 1 or foo > 12')
0.14941698900656775

>>> timeit.timeit('foo_with_bool(0)', 'def foo_with_bool(foo): return foo < 1 or foo > 12')
0.13042642804794014

O range é bem mais caro:

>>> timeit.timeit('foo_with_range(2)', 'def foo_with_range(foo): return foo in range(1,13)')
0.5332381980260834

>>> timeit.timeit('foo_with_range(0)', 'def foo_with_range(foo): return foo in range(1,13)')
0.44614369003102183

Mas então fiz um ajuste no seu código para reproduzir true quando o valor for dentro do intervalo, simulando a lógica do in:

>>> timeit.timeit('foo_with_bool(0)', 'def foo_with_bool(foo): return foo >= 1 and foo < 13')
0.12621068698354065

>>> timeit.timeit('foo_with_bool(1)', 'def foo_with_bool(foo): return foo >= 1 and foo < 13')
0.14314978604670614

>>> timeit.timeit('foo_with_bool(12)', 'def foo_with_bool(foo): return foo >= 1 and foo < 13')
0.1501423100125976

>>> timeit.timeit('foo_with_bool(13)', 'def foo_with_bool(foo): return foo >= 1 and foo < 13')
0.1478095329948701

Então troquei o range pela tupla e o in ficou bem rápido no melhor caso. Mais rápido até que a comparação:

>>> timeit.timeit('with_in(0)', 'def with_in(foo): return foo in (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)')
0.2828292379854247

>>> timeit.timeit('with_in(1)', 'def with_in(foo): return foo in (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)')
0.11704596801428124

>>> timeit.timeit('with_in(12)', 'def with_in(foo): return foo in (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)')
0.2894133450463414

>>> timeit.timeit('with_in(13)', 'def with_in(foo): return foo in (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)')
0.31002350500784814

No dis dá pra ver que a tupla literal vira um LOAD_CONST:

>>> dis.dis(with_in)
  1           0 LOAD_FAST                0 (foo)
              3 LOAD_CONST              13 ((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12))
              6 COMPARE_OP               6 (in)
              9 RETURN_VALUE

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment