Domanda

  1. C'è un problema di prestazioni o di manutenzione del codice di problema con l'utilizzo di assert come parte del codice standard invece di usarlo solo per scopi di debug?

    È

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

    meglio o peggio

    if x < 0:
        raise Exception, 'x is less than zero'
    
  2. Inoltre, c'è un modo per impostare una regola di business come if x < 0 raise error che è sempre controllato senza try/except/finally così, se in un qualsiasi momento, in tutto il codice x è inferiore a 0, viene generato un errore, come se si imposta assert x < 0 all'inizio di una funzione, in qualsiasi punto all'interno della funzione in cui x diventa meno di 0 viene sollevata un'eccezione?

È stato utile?

Soluzione

Per essere in grado di lanciare automaticamente un errore quando x diventano meno di zero per tutta la funzione. È possibile utilizzare descrittori di classe . Ecco un esempio:

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

Altri suggerimenti

afferma dovrebbe essere usato per testare le condizioni che non dovrebbe mai accadere . Lo scopo è quello di mandare in crash presto nel caso di un programma di Stato corrotto.

Le eccezioni devono essere utilizzati per gli errori che possono plausibilmente accadere, e si dovrebbe quasi sempre creare le proprie classi di eccezione .


Ad esempio, se si sta scrivendo una funzione per leggere da un file di configurazione in un dict, formattazione erronea nel file dovrebbe sollevare una ConfigurationSyntaxError, mentre è possibile assert che non sei in procinto di tornare None.


Nel tuo esempio, se x è un valore impostato tramite un'interfaccia utente o da una fonte esterna, un'eccezione è meglio.

Se x è impostato solo dal codice all'interno dello stesso programma, andare con un'asserzione.

affermazioni "assert" vengono rimossi quando la compilazione è ottimizzato . Quindi, sì, ci sono sia le prestazioni e le differenze funzionali.

  

Il generatore di codice attuale non emette codice per un'istruzione di asserzione quando l'ottimizzazione è richiesto al momento della compilazione. - Python 2.6.4 Docs

Se si utilizza assert per implementare funzionalità dell'applicazione, quindi ottimizzare la distribuzione della produzione, vi sarà afflitto da difetti "ma-da-lavori-in-dev".

PYTHONOPTIMIZE e - O -OO

I quattro scopi della assert

Si supponga di lavorare su 200.000 righe di codice con quattro colleghi Alice, Bernd, Carl, e Daphne.Chiamano il codice, è possibile chiamare il loro codice.

Quindi assert ha quattro ruoli:

  1. Informare Alice, Bernd, Carl, e Daphne che il codice prevede.
    Si supponga di disporre di un metodo che elabora una lista di tuple e della logica di programma, può rompersi se le tuple non sono immutabili:

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

    Questo è più affidabile di informazioni equivalenti nella documentazione e molto più facile da mantenere.

  2. Informare il computer che il codice prevede.
    assert impone un comportamento corretto da chiamanti di codice.Se il codice chiama Alices e Bernd il codice chiama il tuo, poi senza la assert, se il programma si blocca in Alices codice, Bernd potrebbe pensare che era Alice colpa, Alice approfondisce e si potrebbe pensare che era colpa tua, si indagare e raccontare Bernd è stato, infatti, il suo.Un sacco di lavoro perso.
    Con asserisce, chi riceve una chiamata sbagliata, che sarà presto in grado di vedere che era colpa loro, non tuo.Alice, Bernd, e tutto il beneficio.Consente di risparmiare una quantità immensa di tempo.

  3. Informare i lettori di codice (compreso te) che il codice ha raggiunto a un certo punto.
    Si supponga di disporre di un elenco di voci, e ciascuna di esse può essere pulito (che è buono) oppure può essere smorsh, trale, gullup, o scintillavano (che non sono tutti accettabili).Se è smorsh deve essere unsmorshed;se è trale deve essere baludoed;se è gullup deve essere tirato (e quindi, possibilmente veloce, troppo);se è scintillavano, deve essere brillarono di nuovo, tranne il giovedì.Si ottiene l'idea:È complicato roba.Ma il risultato finale è (o dovrebbe essere) che tutte le voci siano puliti.La Cosa Giusta(TM) di fare è quello di riassumere l'effetto ciclo di pulizia

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

    Questo bilancio permette di risparmiare un mal di testa per tutti, cercando di capire cosa esattamente è che il meraviglioso ciclo di raggiungere.E la più frequente di queste persone probabilmente essere te stesso.

  4. Informare il computer che il tuo codice è stato raggiunto ad un certo punto.
    Si dovrebbe mai dimenticare il ritmo di una voce che si è verificato dopo il trotto il assert salva il tuo giorno e di evitare che il codice pause cara Dafne molto più tardi.

Nella mia mente, assertdue fini della documentazione (1 e 3) e salvaguardia (2 e 4) sono ugualmente importanti.
Informare le persone possono anche essere più prezioso di informare il computer per evitare che il molto di errori il assert mira a catturare (nel caso 1) e un sacco di successivi errori, in ogni caso.

In aggiunta alle altre risposte, afferma stessi generare eccezioni, ma solo AssertionErrors. Da un punto di vista utilitaristico, affermazioni non sono adatti per quando è necessario il controllo a grana fine su cui si cattura eccezioni.

L'unica cosa che è veramente sbagliato con questo approccio è che è difficile fare un'eccezione molto descrittivo utilizzando le istruzioni assert. Se siete alla ricerca per la sintassi più semplice, ricorda che possono fare anche qualcosa di simile:

class XLessThanZeroException(Exception):
    pass

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

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

Un altro problema è che l'utilizzo affermare per il normale condizione controllo è che rende difficile per disattivare il debugging afferma utilizzando il flag -O.

Come si è detto in precedenza, le affermazioni devono essere utilizzati quando il codice NON DEVONO mai raggiungere un punto, significa che non c'è un bug lì. Probabilmente la ragione più utile che posso vedere di utilizzare un affermazione è un invariante / pre / post-condizione. Si tratta di qualcosa che deve essere vero all'inizio o alla fine di ogni iterazione di un ciclo o una funzione.

Per esempio, una funzione ricorsiva (2 funzioni separate così 1 gestisce male ingresso e l'altro gestisce codice cattivo, perché è difficile distinguere con ricorsione). Questo renderebbe evidente se ho dimenticato di scrivere l'istruzione if, cosa fosse andato storto.

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

Queste invarianti di ciclo spesso possono essere rappresentati con un'affermazione.

Lingua inglese word affermare qui è usato nel senso di giuro, affermare, confessare.Ciò non significa che "check" o "dovrebbe essere".Significa che si come coder stanno facendo un dichiarazione giurata qui:

# 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 il codice è corretto, salvo Singolo evento sconvolge, guasti hardware e tali, non affermare mai fallire.Che è il motivo per cui il comportamento del programma per un utente finale non deve essere pregiudicata.In particolare, un'asserzione non può fallire, anche sotto eccezionali condizioni programmatiche.Semplicemente non ha mai accadere.Se succede, il programmatore deve essere zapped per esso.

è c'è un problema di prestazioni?

  • Si ricorda a "farlo funzionare prima di farlo funzionare veloce" .
    Molto piccola percentuale di qualsiasi programma di solito sono rilevanti per la sua velocità. È sempre possibile cacciare o semplificare un assert se mai si rivela essere un problema di prestazioni -. e la maggior parte di loro non lo farà mai

  • Essere pragmatici :
    Si supponga di avere un metodo che elabora una lista non vuota di tuple e della logica del programma si romperà se tali tuple non sono immutabili. Si dovrebbe scrivere:

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

    Questo è probabilmente bene se le vostre liste tendono ad essere lunga dieci voci, ma può diventare un problema se hanno un milione di voci. Ma piuttosto che scartando questo controllo prezioso del tutto è possibile semplicemente downgrade a

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

    che è economico ma è probabile che cattura la maggior parte del reale errori di programma in ogni caso.

C'è un quadro chiamato JBoss Drools per Java che fa il monitoraggio runtime per far valere le regole di business, che risponde alla seconda parte della tua domanda. Tuttavia, non sono sicuro se c'è un tale quadro per Python.

un'asserzione è quello di verificare -
1. la condizione valida,
2. la dichiarazione valida,
3. vera logica;
del codice sorgente. Invece di fallire l'intero progetto dà un allarme che qualcosa non è appropriata nel file di origine.

Nell'esempio 1, dal momento che 'str' variabile non è nul. Quindi nessun qualsiasi valere o eccezioni vengono sollevate.

Esempio 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

Nell'esempio 2, var 'str' è nul. Quindi stiamo salvando l'utente di andare avanti di programma difettoso da assert dichiarazione.

Esempio 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

Nel momento in cui non si vuole eseguire il debug e realizzato il problema asserzione nel codice sorgente. Disattivare il flag di ottimizzazione

python -O assertStatement.py
nulla otterrà Stampa

In quali di PTVS, PyCharm IDE, le dichiarazioni assert isinstance() Ala possono essere utilizzate per consentire il completamento del codice per alcuni oggetti poco chiare.

Se hai a che fare con il codice legacy che si basa su assert per funzionare correttamente, anche se non dovrebbe , poi aggiungendo il seguente codice è una soluzione rapida fino a trovare il tempo di refactoring:

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
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top