Eu tenho uma instrução in if-elif-elif-else na qual 99% das vezes, a instrução else é executada:
if something == 'this':
doThis()
elif something == 'that':
doThat()
elif something == 'there':
doThere()
else:
doThisMostOfTheTime()
Essa construção é feita muito , mas como ela examina todas as condições antes de atingir o else, tenho a sensação de que não é muito eficiente, muito menos Pythônico. Por outro lado, ele precisa saber se alguma dessas condições foi atendida, portanto, deve testá-la de qualquer maneira.
Alguém sabe se e como isso poderia ser feito de forma mais eficiente ou esta é simplesmente a melhor maneira possível de fazê-lo?
python
performance
if-statement
Kramer65
fonte
fonte
sort
acorrentar as coisas que está executando seu if / else ... de modo que todos os elementos que uma das condições corresponderá estejam em uma extremidade e todos os demais estejam na outra? Se sim, você pode ver se isso é mais rápido / mais elegante ou não. Mas lembre-se, se não houver problema de desempenho, é muito cedo para se preocupar com a otimização.if not something.startswith("th"): doThisMostOfTheTime()
e fazer outra comparação naelse
cláusula.something
, ou comparações semelhantes são realizadas várias vezes no mesmo valor?Respostas:
O código...
... parece que deveria ser mais rápido, mas na verdade é mais lento do que a construção
if
...elif
...else
, porque tem que chamar uma função, o que pode ser uma sobrecarga de desempenho significativa em um loop fechado.Considere estes exemplos ...
1.py
2.py
3.py
4.py
... e observe a quantidade de tempo de CPU que eles usam ...
... usando o tempo do usuário de
time(1)
.A opção nº 4 tem a sobrecarga de memória adicional de adicionar um novo item para cada falha de chave distinta, então se você está esperando um número ilimitado de falhas de chave distintas, eu escolheria a opção nº 3, que ainda é uma melhoria significativa em a construção original.
fonte
dict
é mais lento, mas então seus tempos mostram que é a segunda opção mais rápida.dict.get()
é mais lento, que é2.py
- o mais lento de todos.Eu criaria um dicionário:
Agora use apenas:
Se
something
não for encontrado nooptions
dicionário, entãodict.get
retornará o valor padrãodoThisMostOfTheTime
Algumas comparações de tempo:
Roteiro:
Resultados:
Para
10**5
chaves inexistentes e 100 chaves válidas:Portanto, para um dicionário normal, a verificação da chave
key in options
é a maneira mais eficiente aqui:fonte
options = collections.defaultdict(lambda: doThisMostOfTheTime, {'this': doThis,'that' :doThat, 'there':doThere}); options[something]()
é marginalmente mais eficiente.options
dicionário para evitar reconstruí-lo, movendo assim parte (mas não toda) da lógica para longe do ponto de uso. Ainda assim, belo truque!try: options[key]() except KeyError: doSomeThingElse()
(já queif key in options: options[key]()
você está pesquisando duas vezes no dicionário porkey
Você consegue usar o pypy?
Manter o código original, mas executá-lo em pypy, dá uma aceleração de 50x para mim.
CPython:
Pypy:
fonte
Aqui está um exemplo de um if com condições dinâmicas traduzido para um dicionário.
É uma forma, mas pode não ser a forma mais pitônica de fazê-lo, porque é menos legível para quem não é fluente em Python.
fonte
As pessoas alertam
exec
por motivos de segurança, mas este é um caso ideal para isso.É uma máquina de estado fácil.
fonte