La meilleure pratique pour Python assert

  1. L'utilisation de assert dans le code standard au lieu de l'utiliser uniquement à des fins de débogage pose-t-elle un problème de performance ou de maintenance du code?

    Est

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

    meilleure ou pire que

    if x < 0:
        raise Exception, 'x is less than zero'
    
  2. aussi, y a-t-il un moyen de définir une règle d'affaires comme if x < 0 raise error qui est toujours cochée sans le try/except/finally donc, si à tout moment tout au long du code x est inférieur à 0 une erreur est soulevée, comme si vous mettez assert x < 0 au début d'une fonction, n'importe où dans la fonction où x devient moins que 0 une exception est soulevée?

397
demandé sur codeforester 2009-06-03 16:57:16

13 réponses

pour être en mesure de lancer automatiquement une erreur lorsque x devient inférieur à zéro tout au long de la fonction. Vous pouvez utiliser descripteurs de classe . Voici un exemple:

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
132
répondu Nadia Alramli 2015-12-02 15:24:18

affirme devrait être utilisé pour tester les conditions que ne devrait jamais se produire . Le but est de s'écraser tôt dans le cas d'un État de programme corrompu.

les Exceptions doivent être utilisées pour les erreurs qui peuvent éventuellement se produire, et vous devez presque toujours créer vos propres classes D'Exception .


par exemple, si vous écrivez une fonction pour lire à partir d'un fichier de configuration dans un dict , le formatage inapproprié dans le fichier devrait soulever un ConfigurationSyntaxError , tandis que vous pouvez assert que vous n'êtes pas sur le point de retourner None .


dans votre exemple, si x est une valeur définie via une interface utilisateur ou à partir d'une source externe, une exception est préférable.

si x n'est défini que par votre propre code dans le même programme, allez avec une affirmation.

645
répondu Deestan 2018-06-19 17:12:55

"affirmer" les énoncés sont supprimés lorsque la compilation est optimisée . Donc, oui, il y a à la fois des différences de rendement et des différences fonctionnelles.

le générateur de code actuel n'émet aucun code pour une déclaration assert lorsque l'optimisation est demandée au moment de la compilation. - Python 2.6.4 Docs

si vous utilisez assert pour mettre en œuvre la fonctionnalité de l'application, puis optimiser le déploiement à la production, vous serez victime de défauts "mais-it-works-in-dev".

voir PYTHONOPTIMIZE et - O -OO

314
répondu John Mee 2011-06-08 00:40:38

les quatre buts de assert

supposons que vous travailliez sur 200 000 lignes de code avec quatre collègues Alice, Bernd, Carl et Daphne. Ils appellent votre code, vous appelez leur code.

puis assert a quatre rôles :

  1. informez Alice, Bernd, Carl et Daphne de ce que votre code attend.

    Supposons que vous avez un méthode qui traite une liste de tuples et la logique du programme peut se casser si ces tuples ne sont pas immuables:

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

    C'est plus fiable que l'information équivalente dans la documentation et beaucoup plus facile à entretenir.

  2. " informez l'ordinateur de ce que votre code attend.

    assert impose un comportement correct de la part des appelants de votre code. Si votre code appelle Le code d'Alices et de Bernd appelle le vôtre., puis sans le assert , si le programme tombe en panne dans le code Alices, Bernd pourrait penser que C'est la faute D'Alice., Alice enquête et pourrait penser que c'est ta faute., vous enquêtez et dites à Bernd que C'était le sien. Beaucoup de travail perdues.

    Avec asserts, celui qui reçoit un mauvais appel, ils seront rapidement en mesure de voir qu'il était de leur faute, pas la vôtre. Alice, Bernd et vous en bénéficiez tous. Sauve énormément de temps.

  3. " informez les lecteurs de votre code (y compris vous-même) ce que votre code a atteint à un moment donné.

    Supposons que vous disposez d'une liste d'entrées, et chacun d'eux peut être propre (ce qui est bon) ou il peut être smorsh, trale, gullup, ou twinkled (qui sont pas acceptables). Si c'est smorsh il doit être unsmorshed; si c'est trale il doit être baludoed; s'il est goullup il doit être trotté (et puis éventuellement rythmé, aussi); si il doit encore scintiller, sauf le jeudi. Vous avez l'idée: C'est compliqué tout ça. Mais le résultat final est (ou devrait être) que toutes les entrées sont propres. La bonne chose à faire est de résumer l'effet de votre boucle de nettoyage en tant que

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

    ces déclarations épargne un mal de tête pour tout le monde essayant de comprendre ce que exactement c'est que la boucle merveilleuse est en train de réaliser. Et le plus fréquent de ces personnes sera probablement m'.

  4. " informez l'ordinateur de ce que votre code a atteint à un moment donné.

    Si jamais vous oubliez de faire une entrée qui en a besoin après avoir trotté, le assert sauvera votre journée et éviter que votre code la chère Daphné est cassée bien plus tard.

Dans mon esprit, assert 's deux fins de documentation (1 et 3) et sauvegarde (2 et 4) sont également précieux.

Informer la population peut même être plus précieux que d'informer l'ordinateur parce qu'il peut prévenir les erreurs mêmes que le assert vise à attraper (dans le cas 1) et beaucoup d'erreurs ultérieures dans tous les cas.

109
répondu Lutz Prechelt 2018-03-23 13:33:21

en plus des autres réponses, affirme eux-mêmes jeter des exceptions, mais seulement des erreurs assertion. D'un point de vue utilitaire, les assertions ne sont pas adaptées pour quand vous avez besoin de contrôle de grain fin sur les exceptions que vous attrapez.

19
répondu outis 2009-12-03 11:37:29

la seule chose qui ne va pas dans cette approche, c'est qu'il est difficile de faire une exception très descriptive en utilisant les affirmations assert. Si vous cherchez la syntaxe plus simple, rappelez-vous que vous peut aussi faire quelque chose comme ceci:

class XLessThanZeroException(Exception):
    pass

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

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

un autre problème est que l'utilisation d'assert pour la vérification des conditions normales rend difficile la désactivation du débogage asserts à l'aide du drapeau-O.

18
répondu Jason Baker 2009-06-03 13:12:25

comme cela a été dit précédemment, les assertions doivent être utilisées lorsque votre code ne doit jamais atteindre un point, ce qui signifie qu'il y a un bug. Probablement la raison la plus utile que je peux voir pour utiliser une assertion est un invariant/pre/postcondition. Ce sont quelque chose qui doit être vrai au début ou à la fin de chaque itération d'une boucle ou d'une fonction.

par exemple, une fonction récursive (2 fonctions séparées donc 1 gère la mauvaise entrée et l'autre gère le mauvais code, parce que c'est dur à distinguer avec récursion). Cela le rendrait évident si j'ai oublié d'écrire la déclaration si, ce qui a mal tourné.

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

ces invariants de boucle peuvent souvent être représentés par une assertion.

7
répondu matts1 2013-03-07 09:46:19

La langue anglaise, le mot assert est ici utilisé dans le sens de jure , affirmer , avoue . Il ne signifie pas " check " ou " devrait être " . Cela signifie que vous comme un codeur font un assermenté déclaration ici:

# 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

Si le code est correct, sauf Seul événement bouleverse , les pannes de matériel et de ces, pas d'affirmer seront jamais échouer . C'est pourquoi le comportement du programme à un utilisateur final ne doit pas être touchée. En particulier, une affirmation ne peut pas échouer même sous conditions programmatiques exceptionnelles . Juste qu'il n'arrivera jamais. Si cela se produit, le programmeur doit être zappé.

3
répondu Antti Haapala 2017-12-09 18:43:55

est-ce que y a un problème de performance?

  • s'il vous Plaît n'oubliez pas de "faire fonctionner en premier avant de faire fonctionner rapide" .

    Très peu de pour cent d'un programme sont habituellement pertinents pour sa vitesse. Vous pouvez toujours jeter ou simplifier un assert si jamais il s'avère être un problème de performance -- et la plupart d'entre eux ne le sera jamais.

  • pragmatique :

    Supposons que vous ayez une méthode qui traite une liste non vide de tuples et que la logique du programme se casse si ces tuples ne sont pas immuables. Vous devez écrire:

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

    c'est probablement très bien si vos listes ont tendance à être longues de dix entrées, mais il peut devenir un problème si ils ont un million d'entrées. Mais plutôt que de rejeter entièrement ce précieux chèque, vous pourriez simplement dégrader à

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

    ce qui est bon marché mais va probablement attraper la plupart des erreurs de programme " actuel de toute façon.

3
répondu Lutz Prechelt 2018-04-11 07:04:11

Il ya un cadre appelé JBoss baves pour java qui ne runtime monitoring d'affirmer des règles d'affaires, qui répond à la deuxième partie de votre question. Cependant, je ne suis pas sûr qu'il existe un tel cadre pour python.

1
répondu Raffi Khatchadourian 2011-10-13 20:15:01

une affirmation est à vérifier -

1. la condition valide,

2. la déclaration valide,

3. véritable logique;

de code source. Au lieu d'échouer le projet entier il donne une alarme que quelque chose n'est pas approprié dans votre fichier source.

dans l'exemple 1, puisque la variable " str " n'est pas nul. Donc aucune affirmation ou exception ne sera soulevée.

exemple 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

dans l'exemple 2, var 'str' est nul. Donc nous sauvons l'utilisateur d'aller en avant du programme défectueux par affirmer déclaration.

exemple 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

le moment où nous ne voulons pas de débogage et réalisé le problème d'assertion dans le code source. Désactiver le drapeau d'optimisation

python-O assertStatement.py

rien ne pourra obtenir d'impression

1
répondu akD 2016-10-18 04:21:06

dans les IDE tels que PTVS, PyCharm, Wing assert isinstance() déclarations peuvent être utilisés pour activer l'achèvement de code pour certains objets imprécis.

0
répondu denfromufa 2015-04-08 17:40:32

si vous avez affaire au Code d'héritage qui s'appuie sur assert pour fonctionner correctement, même si il ne devrait pas , alors ajouter le code suivant est une solution rapide jusqu'à ce que vous trouvez le temps de refactor:

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
-1
répondu Emilio M Bumachar 2018-03-23 13:56:05