Pergunta

  1. Existe um problema de desempenho ou a manutenção do código com o uso assert como parte do código padrão em vez de usá-lo apenas para fins de depuração?

    é

    assert x >= 0, 'x is less than zero'
    

    melhor ou pior do que

    if x < 0:
        raise Exception, 'x is less than zero'
    
  2. Além disso, existe alguma maneira para definir uma regra de negócio como if x < 0 raise error que é sempre verificada sem a try/except/finally assim, se a qualquer momento durante todo o x código é menor que 0 é accionado um erro, como se você conjunto assert x < 0 em o início de uma função, em qualquer lugar dentro da função onde x torna-se menos, em seguida, 0 uma exceção?

Foi útil?

Solução

Para ser capaz de lançar automaticamente um erro quando x tornar-se menos do que zero em toda a função. Você pode usar href="http://docs.python.org/reference/datamodel.html#implementing-descriptors" descritores de classe . Aqui está um exemplo:

class LessThanZeroException(Exception):
    pass

class variable(object):
    def __init__(self, value=0):
        self.__x = value

    def __set__(self, obj, value):
        if value < 0:
            raise LessThanZeroException('x is less than zero')

        self.__x  = value

    def __get__(self, obj, objType):
        return self.__x

class MyClass(object):
    x = variable()

>>> m = MyClass()
>>> m.x = 10
>>> m.x -= 20
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "my.py", line 7, in __set__
    raise LessThanZeroException('x is less than zero')
LessThanZeroException: x is less than zero

Outras dicas

afirma deve ser usado para condições de teste que nunca deveria acontecer . O objetivo é bater cedo no caso de um estado programa corrupto.

As excepções devem ser usados ??para erros que podem concebivelmente acontecer, e você deve quase sempre criar suas próprias classes de exceção .


Por exemplo, se você está escrevendo uma função para ler a partir de um arquivo de configuração em um dict, formatação inadequada no arquivo deve levantar uma ConfigurationSyntaxError, enquanto você pode assert que você não está prestes a None retorno.


No seu exemplo, se x é um valor definido por meio de uma interface de utilizador ou a partir de uma fonte externa, uma exceção é o melhor.

Se x só é definido por seu próprio código no mesmo programa, ir com uma afirmação.

declarações "assert" são removidos quando a compilação é otimizado . Então, sim, há tanto o desempenho e diferenças funcionais.

O gerador de código atual não emite código para uma instrução assert quando a otimização é solicitado em tempo de compilação. - Python 2.6.4 Docs

Se você usar assert para implementar a funcionalidade do aplicativo, em seguida, otimizar a implantação de produção, você será atormentado por "mas-it-obras em dev" defeitos.

PYTHONOPTIMIZE e - O -OO

Os quatro fins de assert

Suponha que você trabalha em 200.000 linhas de código com quatro colegas Alice, Bernd, Carl, e Daphne. Eles chamam seu código, você chamar seu código.

Então assert tem quatro papéis :

  1. Informar Alice, Bernd, Carl, e Daphne o que sua espera de código.
    Suponha que você tenha um método que processa uma lista de tuplas e a lógica do programa pode quebrar se essas tuplas não são imutáveis:

    def mymethod(listOfTuples):
        assert(all(type(tp)==tuple for tp in listOfTuples))
    

    Este é mais confiável do que a informação equivalente na documentação e muito mais fácil de manter.

  2. Informar o computador que seus espera de código.
    assert impõe um comportamento adequado dos chamadores do seu código. Se seu código chama sua chama o código de Bernd das Alices e, em seguida, sem a assert, se o programa trava em código Alices, Bernd poderia supor que a culpa era de Alice, Alice investiga e pode-se supor que foi sua culpa, você investigar e dizer Bernd era de fato sua. Muito trabalho perdido.
    Com afirma, quem recebe um erro chamada, eles rapidamente ser capaz de ver que era culpa deles, não seu. Alice, Bernd, e você todo o benefício. Salva imensas quantidades de tempo.

  3. Informar os leitores do seu código (incluindo você) que seu código tem alcançado em algum ponto.
    Suponha que você tenha uma lista de entradas e cada um deles pode ser limpo (que é bom) ou ele pode ser smorsh, Trale, gullup, ou cintilado (que não são aceitáveis). Se é smorsh deve ser unsmorshed; se é Trale deve ser baludoed; se é gullup deve ser trotou (e então possivelmente ritmo, também); se for brilharam deve ser brilharam novamente, exceto às quintas-feiras. Você começa a idéia: É uma coisa complicada. Mas o resultado final é (ou deveria ser) que todas as entradas estão limpos. A Coisa Certa (TM) para fazer é resumir o efeito da sua a limpeza do circuito como

    assert(all(entry.isClean() for entry in mylist))
    

    Este declarações salva uma dor de cabeça para todos tentando entender o exatamente é que o laço maravilhoso está conseguindo. E o mais frequente dessas pessoas provavelmente vai ser você mesmo.

  4. Informar o computador o seu código tem alcançado em algum ponto.
    Se você esquecer a andar uma entrada precisar dele depois de trote, o assert vai salvar o seu dia e evitar que o seu código breaks querido muito mais tarde.

  5. Daphne

Em minha mente, assert é dois fins de documentação (1 e 3) e salvaguarda (2 e 4) são igualmente valiosas.
Informando as pessoas podem até ser mais valioso do que informando o computador porque ele pode impedir as erros os objetivos assert de captura (no caso 1) e muitos erros subseqüentes, em qualquer caso.

Além das outras respostas, afirma-se lançar exceções, mas apenas AssertionErrors. Do ponto de vista utilitário, afirmações não são adequados para quando você precisa de um controle de grão fino sobre o qual as exceções que você pegar.

A única coisa que está realmente errado com esta abordagem é que é difícil fazer uma exceção muito descritivo, com instruções Assert. Se você está procurando a sintaxe mais simples, lembre-se que você pode também fazer algo como isto:

class XLessThanZeroException(Exception):
    pass

def CheckX(x):
    if x < 0:
        raise XLessThanZeroException()

def foo(x):
    CheckX(x)
    #do stuff here

Outro problema é que o uso de assert para a condição de verificação normal é que ela torna mais difícil para desativar a depuração afirma usando o sinalizador -o.

Como já foi dito anteriormente, afirmações deve ser usado quando o código não deve nunca chegar a um ponto, o que significa que há um bug lá. Provavelmente a razão mais útil que pode ver de usar uma afirmação é uma invariante / pre / pós-condição. Estes são algo que deve ser verdadeiro no início ou no final de cada iteração de um loop ou uma função.

Por exemplo, uma função recursiva (2 funções separadas de modo 1 alças má entrada ea outras alças código ruim, porque é difícil distinguir com recursão). Isso tornaria óbvio, se eu esqueci de escrever a instrução if, o que tinha de errado embora.

def SumToN(n):
    if n <= 0:
        raise ValueError, "N must be greater than or equal to 0"
    else:
        return RecursiveSum(n)

def RecursiveSum(n):
    #precondition: n >= 0
    assert(n >= 0)
    if n == 0:
        return 0
    return RecursiveSum(n - 1) + n
    #postcondition: returned sum of 1 to n

Estes invariantes de laço muitas vezes pode ser representado com uma afirmação.

A palavra do idioma Inglês assert aqui é usado no sentido de jura , afirmam , avow . Isso não significa "verificação" ou "deve ser" . Isso significa que você como um codificador está fazendo um declaração juramentada aqui:

# I solemnly swear that here I will tell the truth, the whole truth, 
# and nothing but the truth, under pains and penalties of perjury, so help me FSM
assert answer == 42

Se o código está correto, salvo Single-evento viradas , falhas de hardware e tal, < strong> não assert nunca vai falhar . É por isso que o comportamento do programa para um usuário final não deve ser afectado. Especialmente, uma declaração não pode falhar, mesmo sob condições programáticas excepcionais . Ele simplesmente não acontecer. Se isso acontecer, o programador deve ser eletrocutado por isso.

é há um problema de desempenho?

  • Por favor, lembre-se de "fazê-lo funcionar antes de você fazer o trabalho rápido" .
    Muito poucos por cento de qualquer programa são geralmente relevantes para a sua velocidade. Você sempre pode expulsar ou simplificar um assert se ele nunca prova ser um problema de desempenho -. ea maioria deles nunca será

  • Ser pragmático :
    Suponha que você tenha um método que processa uma lista não-vazia de tuplas e a lógica do programa vai quebrar se essas tuplas não são imutáveis. Você deve escrever:

    def mymethod(listOfTuples):
        assert(all(type(tp)==tuple for tp in listOfTuples))
    

    Este é provavelmente bom se suas listas tendem a ser as entradas dez muito tempo, mas ele pode se tornar um problema se eles têm um milhão de entradas. Mas ao invés de descartar este valioso verificação inteiramente você poderia simplesmente fazer o downgrade para

    def mymethod(listOfTuples):
        assert(type(listOfTuples[0])==tuple)  # in fact _all_ must be tuples!
    

    que é barato, mas provavelmente vai pegar a maioria dos erros reais do programa de qualquer maneira.

Há um quadro chamado JBoss Drools para java que não runtime monitoramento de regras de negócios afirmam, que responde à segunda parte da sua pergunta. No entanto, tenho a certeza se é que existe tal estrutura para python.

Um Assert é verificar -
1. a condição válida,
2. a declaração válida,
3. verdadeira lógica;
de código fonte. Em vez de deixar todo o projeto dá um alarme de que algo não é apropriado em seu arquivo de origem.

No exemplo 1, desde variável 'str' não é nul. Portanto, não qualquer assert ou exceção se levantou.

Exemplo 1:

#!/usr/bin/python

str = 'hello Pyhton!'
strNull = 'string is Null'

if __debug__:
    if not str: raise AssertionError(strNull)
print str

if __debug__:
    print 'FileName '.ljust(30,'.'),(__name__)
    print 'FilePath '.ljust(30,'.'),(__file__)


------------------------------------------------------

Output:
hello Pyhton!
FileName ..................... hello
FilePath ..................... C:/Python\hello.py

No exemplo 2, var 'str' é nul. Portanto, estamos a poupar o usuário de ir à frente do programa defeituoso por assert comunicado.

Exemplo 2:

#!/usr/bin/python

str = ''
strNull = 'NULL String'

if __debug__:
    if not str: raise AssertionError(strNull)
print str

if __debug__:
    print 'FileName '.ljust(30,'.'),(__name__)
    print 'FilePath '.ljust(30,'.'),(__file__)


------------------------------------------------------

Output:
AssertionError: NULL String

No momento nós não queremos depuração e percebeu a questão afirmação no código fonte. Desativar a bandeira otimização

python -O assertStatement.py
nada terá de impressão

O IDE Em tais como PTVs, PyCharm, Asa declarações assert isinstance() pode ser usado para permitir a conclusão de código para alguns objetos pouco claras.

Se você está lidando com código legado que se baseia em assert para funcionar corretamente, embora não deve , em seguida, adicionando o seguinte código é uma solução rápida até encontrar tempo para refatorar:

try:
    assert False
    raise Exception('Python Assertions are not working. This tool relies on Python Assertions to do its job. Possible causes are running with the "-O" flag or running a precompiled (".pyo" or ".pyc") module.')
except AssertionError:
    pass
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top