Question

  1. Y at-il un problème d'entretien ou de la performance de code à l'utilisation assert dans le cadre du code standard au lieu de l'utiliser uniquement pour des fins de débogage?

    est

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

    meilleur ou pire que

    if x < 0:
        raise Exception, 'x is less than zero'
    
  2. Aussi, est-il possible de définir une règle d'affaires comme if x < 0 raise error qui est toujours vérifiée sans try/except/finally donc, si à tout moment à travers le x de code est inférieure à 0 une erreur est élevée, comme si vous définissez assert x < 0 à le début d'une fonction, partout dans la fonction où x devient inférieur à 0 une exception est levée?

Était-ce utile?

La solution

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

Autres conseils

doit être utilisé AFFIRME pour tester les conditions que ne devrait jamais arriver . Le but est de planter tôt dans le cas d'un état de programme corrompu.

Les exceptions doivent être utilisées pour des erreurs qui peuvent se produire en théorie, et vous devez créer presque toujours 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 incorrect dans le fichier devrait soulever un ConfigurationSyntaxError, alors que vous pouvez assert que vous n'êtes pas sur le point de revenir None.


Dans votre exemple, si x est une valeur définie via une interface utilisateur ou à partir d'une source externe, une exception est le meilleur.

Si x est uniquement définie par votre propre code dans le même programme, rendez-vous avec une affirmation.

déclarations "assert" sont supprimés lorsque la compilation est optimisé . Alors, oui, il y a à la fois les performances et les différences fonctionnelles.

  

Le générateur de code actuel émet pas de code pour une instruction assert quand est demandé au moment de la compilation optimisation. - Python 2.6.4 Docs

Si vous utilisez assert pour implémenter des fonctionnalités de l'application, puis optimiser le déploiement à la production, vous serez en proie à des « mais-ça-marche-en-dev » défauts.

Voir PYTHONOPTIMIZE et - O -OO

Les quatre buts de assert

Supposons que vous travaillez sur 200.000 lignes de code avec quatre collègues Alice, Bernd, Carl et Daphné. Ils appellent votre code, vous appelez leur code.

Alors assert a quatre rôles :

  1. Informer Alice, Bernd, Carl et Daphné ce que votre code attend. Supposons que vous avez une méthode qui traite une liste de tuples et la logique du programme peuvent se briser si ces tuples ne sont pas immuables:

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

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

  2. Informer l'ordinateur ce que votre code attend. assert applique un comportement correct des appelants de votre code. Si votre code appelle pour Alices et le code de Bernd appelle le vôtre, puis sans assert, si le programme se bloque dans le code Alices, Bernd peut supposer qu'il était la faute d'Alice, Alice enquête et pourrait supposer qu'il était de votre faute, vous enquêtez et dire Bernd il était en fait le sien. Beaucoup de travail perdus.
    Avec affirme, celui qui reçoit un appel mauvais, ils seront rapidement en mesure de voir qu'il était leur faute, pas le vôtre. Alice, Bernd, et vous tous bénéficier. Enregistre d'immenses quantités de temps.

  3. Informer les lecteurs de votre code (vous y compris) ce que votre code a atteint à un moment donné. Supposons que vous avez une liste d'entrées et chacun d'eux peut être propre (ce qui est bon) ou il peut être smorsh, Trale, gullup ou scintillait (qui sont tous non acceptable). Si c'est smorsh il doit être unsmorshed; si elle est Trale il faut baludoed; si elle est gullup il doit être trottait (et peut-être arpenté, aussi); si elle est Twinkled il faut scintillait à nouveau, sauf le jeudi. Vous avez l'idée: C'est un truc compliqué. Mais le résultat final est (ou devrait être) que toutes les entrées sont propres. The Right Thing (TM) à faire est de résumer l'effet de votre boucle de nettoyage

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

    Cette instruction enregistre un casse-tête pour tout le monde à essayer de comprendre ce que exactement il est que la boucle merveilleuse atteint. Et la plus fréquente de ces personnes sera probablement vous-même.

  4. Informer l'ordinateur ce que votre code a atteint à un moment donné. Si vous oubliez jamais à arpenter une entrée besoin après trotter, le assert sauvera votre journée et éviter que votre code pauses cher beaucoup plus tard de Daphné.

Dans mon esprit, deux fins de documentation assert (1 et 3) et sauvegarde (2 et 4) sont tout aussi précieux.
Informer les gens peuvent même être plus de valeur que l'information de l'ordinateur car il peut éviter les erreurs mêmes le assert vise à attraper (dans le cas 1) et beaucoup d'erreurs suivantes dans tous les cas.

En plus des autres réponses, s'affirme lancer des exceptions, mais seulement AssertionErrors. D'un point de vue utilitaire, les assertions ne conviennent pas lorsque vous avez besoin un contrôle précis des grains sur lesquels vous attrapez des exceptions.

La seule chose qui est vraiment mal avec cette approche est qu'il est difficile de faire une exception très descriptive en utilisant des instructions assert. Si vous cherchez la syntaxe plus simple, rappelez-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 pour affirmer condition normale vérification est qu'il rend difficile de désactiver le débogage en utilisant affirme le drapeau -O.

Comme il a été dit précédemment, les affirmations doivent être utilisées lorsque votre code ne devrait jamais atteindre un point, ce qui signifie qu'il ya un bug là. Probablement la raison la plus utile que je peux voir 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 une fonction.

Par exemple, une fonction récursive (2 fonctions séparées si une mauvaise gère l'entrée et l'autre gère le code mauvais, car il est difficile de distinguer avec récursion). Cela rendrait évident si j'oublié d'écrire l'instruction if, 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 affirmation.

Le mot de la langue anglaise assert ici est utilisé dans le sens de jurent , AFFIRM , avow . Cela ne signifie pas "vérifier" ou "devrait être" . Cela signifie que en tant que codeur font une déclaration sous serment 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, unique événement sauf , les pannes matérielles et autres, < strong> ne sera jamais assert échec . Voilà pourquoi le comportement du programme à un utilisateur final ne doit pas être affectée. Surtout, une assertion ne peut pas échouer, même dans conditions programmatiques exceptionnelles . Il ne vient jamais se produire. Si cela arrive, le programmeur doit être zappé pour cela.

at-il un problème de performance?

  • S'il vous plaît rappelez-vous à "faire fonctionner d'abord avant de faire fonctionner rapidement" .
    Très peu pour cent de tout programme sont généralement pertinents pour sa vitesse. Vous pouvez toujours chasser ou simplifier une assert si elle prouve jamais un problème de performance -. et la plupart d'entre eux ne le sera jamais

  • Soyez pragmatique :
    Supposons que vous avez une méthode qui traite une liste non vide de tuples et la logique du programme cassera si ces tuples ne sont pas immuables. Vous devez écrire:

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

    Ceci est probablement bien si vos listes ont tendance à être dix entrées long, mais il peut devenir un problème s'ils ont un million d'entrées. Mais plutôt que de jeter cette précieuse vérification entièrement, vous pouvez simplement rétrograder à

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

    qui ne coûte pas cher, mais sera probablement attraper la plupart des réelle erreurs de programme de toute façon.

Il y a un cadre appelé JBoss Drools java qui fait le suivi de l'exécution d'affirmer des règles métier, qui répond à la deuxième partie de votre question. Cependant, je ne suis pas sûr s'il y a un tel cadre pour python.

Un Assertion est de vérifier -
1. la condition valide,
2. la déclaration valide,
3. vraie logique;
du code source. Au lieu de ne pas l'ensemble du projet, il déclenche une alarme que quelque chose ne convient pas dans votre fichier source.

Dans l'exemple 1, puisque la variable 'str' est pas NUL. Donc, pas une exception ou assert sont soulevées.

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 économisons l'utilisateur d'aller de l'avant du programme défectueux par assert 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 nous ne voulons pas debug et a réalisé la question d'assertion dans le code source. Désactiver l'option d'optimisation

python -O assertStatement.py rien ne sera imprimé

Dans IDE tels que PTVs, PyCharm, les déclarations de assert isinstance() Wing peuvent être utilisés pour permettre la complétion de code pour certains objets peu claires.

Si vous avez affaire avec le code existant qui repose sur assert pour fonctionner correctement, même si il ne devrait pas , puis ajoutant le code suivant est une solution rapide jusqu'à ce que vous trouverez le temps de factoriser:

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
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top