Perdão do Python vs. Permissão e Digitação de Pato

42

Em Python, muitas vezes ouço que é melhor "implorar perdão" (exceção de captura) em vez de "pedir permissão" (verificação de tipo / condição). No que diz respeito à aplicação de tipagem de pato em Python, é isso

try:
    x = foo.bar
except AttributeError:
    pass
else:
    do(x)

melhor ou pior que

if hasattr(foo, "bar"):
    do(foo.bar)
else:
    pass

em termos de desempenho, legibilidade, "pythonic" ou algum outro fator importante?

    
por darkfeline 13.11.2012 / 08:37
fonte

4 respostas

58

Isso realmente depende de quantas vezes você acha que a exceção será lançada.

Ambas as abordagens são, na minha opinião, igualmente válidas, pelo menos em termos de legibilidade e pectonias. Mas se 90% dos seus objetos não tiverem o atributo bar , você perceberá uma diferença de desempenho distinta entre as duas abordagens:

>>> import timeit
>>> def askforgiveness(foo=object()):
...     try:
...         x = foo.bar
...     except AttributeError:
...         pass
... 
>>> def askpermission(foo=object()):
...     if hasattr(foo, 'bar'):
...         x = foo.bar
... 
>>> timeit.timeit('testfunc()', 'from __main__ import askforgiveness as testfunc')
2.9459929466247559
>>> timeit.timeit('testfunc()', 'from __main__ import askpermission as testfunc')
1.0396890640258789

Mas se 90% dos seus objetos fizerem ter o atributo, as tabelas serão alteradas:

>>> class Foo(object):
...     bar = None
... 
>>> foo = Foo()
>>> timeit.timeit('testfunc(foo)', 'from __main__ import askforgiveness as testfunc, foo')
0.31336188316345215
>>> timeit.timeit('testfunc(foo)', 'from __main__ import askpermission as testfunc, foo')
0.4864199161529541

Então, do ponto de vista do desempenho, você precisa escolher a abordagem que funciona melhor para suas circunstâncias.

No final, algum uso estratégico do % módulotimeit pode ser a coisa mais pitônica você pode fazer.

    
por 13.11.2012 / 10:24
fonte
9

Em python, muitas vezes você obtém melhor desempenho fazendo as coisas do jeito Python. Com outros idiomas, usar exceções para controle de fluxo é geralmente considerado uma idéia terrível, pois as exceções normalmente impõem uma sobrecarga extraordinária. Mas como essa técnica é explicitamente endossada no Python, o intérprete é otimizado para esse tipo de código.

Como em todas as perguntas de desempenho, a única maneira de ter certeza é o perfil do seu código. Escreva as duas versões e veja qual delas é executada mais rapidamente. Embora, na minha experiência, o "modo Python" seja normalmente o caminho mais rápido.

    
por 13.11.2012 / 08:45
fonte
2

O desempenho, sinto, é uma preocupação secundária. Se surgir, um profiler ajudará você a se concentrar nos gargalos reais, que podem ou não ser como você trata possíveis argumentos ilegais.

A legibilidade e a simplicidade, por outro lado, são sempre uma preocupação primordial. Não há regras rígidas aqui, apenas use seu julgamento.

Esta é uma questão universal, mas as convenções específicas do ambiente ou do idioma são relevantes. Por exemplo, em Python, geralmente é bom simplesmente usar o atributo que você espera e permitir que um possível AttributeError atinja o chamador.

    
por 20.11.2012 / 09:07
fonte
-1

Em termos de correção , acho que o tratamento de exceções é o caminho a seguir (às vezes eu mesmo uso a abordagem hasattr (), embora). O problema básico de confiar em hasattr () é que ele transforma violações de contratos de código em falhas silenciosas (esse é um grande problema no JavaScript, que não utiliza propriedades não existentes).

    
por 10.04.2015 / 16:56
fonte