Devo usar exceções para controlar o intervalo de parâmetros no Python?

5

Por exemplo, para a seguinte assinatura de método:

def genClusters(n_clusters, n_nodes, cluster_distribution):

n_clusters deve ser um número inteiro maior que 1.

n_nodes deve ser um número inteiro maior que n_clusters

cluster_distribution deve ser um float entre 0 e 1.

Devo usar uma série de instruções if then raise exception para lidar com os limites de parâmetro do argumento?

por exemplo:

def genClusters(n_clusters, n_nodes, cluster_distribution):
    if (cluster_distribution < 0 or cluster_distribution > 1):
        raise ValueError("cluster distribution must be between 0 and 1")
    if n_clusters < 1:
         raise ValueError("n_clusters must be at least 1")
    if n_nodes <= n_clusters:
         raise ValueError("n_nodes must be at least n_clusters")

A segunda pergunta é se devo incluir essas instruções de exceção em todos os métodos que também chamam essa.

Por exemplo:

def myFoo(foo, bar, bang):
    clusters = genClusters(foo, bar, bang) 

Nesse cenário, se foo, bar ou bang não se ajustarem a limites de parâmetro definidos anteriormente, uma exceção será lançada quando genClusters for chamado. Então, eu também deveria estar lançando exceções no início de myFoo ?

    
por dwjohnston 23.01.2015 / 02:57
fonte

1 resposta

6

Digamos que você não verifique os argumentos de entrada de antemão e apenas deixe a função seguir seu curso. Considere isto: o que é pior para acontecer? (Esta não é uma pergunta retórica.) Está dando uma entrada ruim para:

  • faz a função falhar com outra exceção em algum lugar no fundo do código?
  • desperdiça muito tempo e falha no meio do caminho?
  • fazer algo potencialmente prejudicial (por exemplo, excluir seus dados importantes ...)?
  • devolve um resultado falso?
  • causa uma mensagem de erro confusa?

Leve isso em consideração com cuidado. Nos cenários mais , onde o desempenho não é da maior importância, você realmente quer que ele falhe cedo e tão alto quanto possível , portanto, verificar argumentos inválidos geralmente é uma boa ideia ( esperamos que responda a sua primeira pergunta).

Isso ajuda a depurar e reduz o risco de seu código fazer algo horrível. Claro, isso pode ser tedioso às vezes, então se você quiser uma abordagem rápida (útil para protótipos), use assert :

assert 0 <= cluster_distribution <= 1

No entanto, não adianta fazê-lo duas vezes se for óbvio que outra função fará isso por você, pois levará à duplicação de código desnecessária (esperamos que responda à sua segunda pergunta).

Por exemplo, digamos que você tenha uma função (um tanto inútil) assim:

def square_root(s);
    return math.sqrt(s)

Não é necessário verificar se s não é negativo porque sqrt já faz isso. Na maioria das funções "pequenas" como essa, você não precisará fazer muita verificação de entrada. Normalmente, apenas as funções "grandes" exigem uma verificação de entrada explícita como essas. Em alguns casos, você pode reestruturar o código sem verificações explícitas, de modo que, se as entradas forem inválidas, elas falharão automaticamente.

    
por 23.01.2015 / 04:00
fonte