Pregunta

  1. ¿Hay un problema de rendimiento o el mantenimiento del código con el uso de assert como parte del código estándar en vez de usarlo sólo para propósitos de depuración?

    es

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

    mejor o peor que

    if x < 0:
        raise Exception, 'x is less than zero'
    
  2. Además, ¿hay alguna manera de establecer una regla de negocio como if x < 0 raise error que siempre se comprueba sin la try/except/finally así, si en algún momento a lo largo del x código es menor que 0 se produce un error, como si se establece assert x < 0 en el inicio de una función, en cualquier lugar dentro de la función donde x se convierte en menos de 0 produce una excepción?

¿Fue útil?

Solución

Para poder lanzar automáticamente un error cuando x se hacen menos que cero durante toda la función. Puede usar descriptores de clase . He aquí un ejemplo:

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

Otros consejos

afirma se debe utilizar para probar las condiciones que no debería ocurrir nunca . El objetivo es chocar temprana en el caso de un estado corrupto programa.

Las excepciones deben ser utilizados por los errores que concebiblemente puede suceder, y usted debe casi siempre crear sus propias clases de excepción .


Por ejemplo, si usted está escribiendo una función para leer desde un archivo de configuración en un dict, formato incorrecto en el archivo debe plantear una ConfigurationSyntaxError, mientras que se puede assert que no estás a punto de volver None.


En su ejemplo, si x es un valor establecido a través de una interfaz de usuario o desde una fuente externa, una excepción es el mejor.

Si x sólo se establece por su propio código en el mismo programa, ir con una afirmación.

estados "valer" se eliminan cuando se optimiza la compilación . Así que, sí, hay tanto el rendimiento y las diferencias funcionales.

  

El generador de código actual emite ningún código de una sentencia assert cuando se solicita la optimización en tiempo de compilación. - Python 2.6.4 Docs

Si utiliza assert para implementar funcionalidad de la aplicación, a continuación, optimizar el despliegue de producción, se verá afectado por "sino-it-obras-en-dev" defectos.

PYTHONOPTIMIZE y - O -OO

Los cuatro efectos de assert

Supongamos que trabaja en 200.000 líneas de código con cuatro colegas Alice, Bernd, Carl, y Daphne. Lo llaman el código, llame a su código.

Entonces assert ha cuatro funciones :

  1. Informar a Alice, Bernd, Carl, y Daphne lo espera su código.
    Suponga que tiene un método que procesa una lista de tuplas y la lógica del programa puede romper si esas tuplas no son inmutables:

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

    Esto es más confiable que la información equivalente en la documentación y mucho más fácil de mantener.

  2. Informar a la computadora lo que espera su código.
    assert impone un comportamiento adecuado de las personas que llaman de su código. Si el código llama código de Alicias y Bernd llama de la suya, a continuación, sin la assert, si se bloquea el programa como código Alicias, Bernd podría asumir que fue culpa de Alice, Alice investiga y podría asumir que era su falta, a investigar y dice Bernd era de hecho su. Mucho trabajo perdidos.
    Con afirma, el que recibe una llamada equivocada, que rápidamente será capaz de ver que era su culpa, no la suya. Alice, Bernd, y que todos se benefician. Ahorra enormes cantidades de tiempo.

  3. Informar a los lectores de su código (incluido usted) lo que el código ha logrado en algún momento.
    Suponga que tiene una lista de entradas y cada uno de ellos puede estar limpio (que es bueno) o puede ser smorsh, Trale, gullup, o centelleó (que todos no son aceptables). Si se trata de smorsh debe ser unsmorshed; si es Trale hay que baludoed; si es gullup se debe al trote (y luego, posiblemente, de ritmo, también); si es brillaron hay que centelleó de nuevo excepto los jueves. Se entiende la idea: Es algo complicado. Pero el resultado final es (o debería ser) que todas las entradas están limpios. The Right Thing (TM) que hacer es resumir el efecto de su bucle de limpieza como

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

    Este declaraciones ahorra un dolor de cabeza para todo el mundo tratando de entender lo que exactamente es que el bucle está logrando maravillosa. Y la más frecuente de estas personas es probable que sea usted mismo.

  4. Informar a la computadora lo que el código ha logrado en algún momento.
    Si alguna vez se olvide de caminar de una entrada que lo necesitan después de trote, la assert ahorrará su día y evitar que su código descansos querida de Daphne mucho más tarde.

En mi mente, dos fines de assert de documentación (1 y 3) y salvaguardia (2 y 4) son igualmente valiosos.
Informar a la gente puede incluso ser más valioso que informando al ordenador ya que puede evitar los mismos errores del assert pretende atrapar (en el caso 1) y un montón de errores posteriores en cualquier caso.

Además de las otras respuestas, afirma a sí mismos lanzar excepciones, pero sólo AssertionErrors. Desde un punto de vista utilitario, las afirmaciones no son adecuados para cuando se necesita el control de grano fino sobre el cual se captura excepciones.

La única cosa que es realmente malo con este enfoque es que es difícil hacer una excepción muy descriptiva usando declaraciones de aserción. Si usted está buscando la sintaxis más simple, recuerde que puede también hacer algo como esto:

class XLessThanZeroException(Exception):
    pass

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

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

Otro problema es que el uso de valer para el normal estado de comprobación es que hace que sea difícil para desactivar la depuración afirma mediante el indicador -O.

Como se ha dicho anteriormente, las afirmaciones deben ser utilizados cuando el código no debe nunca llegar a un punto, es decir, hay un error allí. Probablemente la razón más útil que puedo ver a utilizar una afirmación es un / pre / post-condición invariante. Estos son algo que debe ser verdad al principio o al final de cada iteración de un bucle o una función.

Por ejemplo, una función recursiva (2 funciones separadas de modo 1 maneja mal de entrada y el otro maneja mal código, porque es difícil distinguir con recursividad). Esto haría más evidente si se me olvidó escribir la sentencia si, lo que había salido mal.

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

Estas invariantes de bucle a menudo se pueden representar con una afirmación.

La palabra de la lengua Inglés aserción aquí se utiliza en el sentido de jurar , afirmar , avow . Esto no significa que "verificación" o "debe ser" . Esto significa que como un codificador están haciendo un declaración jurada aquí:

# 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 el código es correcto, salvo un solo evento molesta , fallos de hardware y tal, < strong> ninguna aserción será nunca fallará . Por eso, el comportamiento del programa a un usuario final no debe verse afectado. Sobre todo, una aserción no puede fallar incluso bajo excepcionales condiciones programáticas . Simplemente no sucede nunca. Si esto sucede, el programador debe zapping por ello.

es que hay un problema de rendimiento?

  • Por favor, recuerde a "hacer que funcione primero antes de hacer que funcione rápido" .
    Muy pocos por ciento de cualquier programa suelen ser relevante por su velocidad. Siempre se puede echar a un assert o simplificar si alguna vez se demuestra ser un problema de rendimiento -. y la mayoría de ellos nunca

  • Ser pragmático :
    Suponga que tiene un método que procesa una lista no vacía de tuplas y la lógica del programa se romperá si esas tuplas no son inmutables. Usted debe escribir:

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

    Esto es probablemente muy bien si sus listas tienden a ser diez entradas de largo, pero puede convertirse en un problema si tienen un millón de entradas. Pero en lugar de descartar por completo esta valiosa cheque que podría simplemente rebajar a

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

    que es barato, pero es probable que coger la mayor parte del real errores en los programas de todos modos.

Hay un marco llamado JBoss Drools para Java que hace un seguimiento en tiempo de ejecución para hacer valer las reglas de negocio, que responde a la segunda parte de su pregunta. Sin embargo, no estoy seguro si hay un marco de este tipo de pitón.

una aserción es comprobar -
1. la condición válida, España 2. la declaración válida, España 3. lógica verdadera;
del código fuente. En lugar de fallar todo el proyecto se da una alarma de que algo no es apropiado en el archivo de origen.

En el ejemplo 1, ya que 'str' variable no es nul. Así que no hay ninguna aserción o excepción quedan levantadas.

Ejemplo 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

En el ejemplo 2, var 'str' es nul. Así que estamos ahorrando al usuario de que va por delante de programa defectuosa por sentencia assert.

Ejemplo 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

En el momento en que no queremos depurar y se dio cuenta del problema de aserción en el código fuente. Desactivar el indicador de optimización

pitón -O assertStatement.py
nada va a conseguir de impresión

de como PTVS, PyCharm IDE, declaraciones assert isinstance() Ala se pueden utilizar para permitir la finalización de código para algunos objetos poco claras.

Si usted está tratando con el código heredado que se basa en assert para funcionar correctamente, a pesar de que no debe , a continuación, añadiendo el siguiente código es una solución rápida hasta que encuentre tiempo para refactorizar:

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 bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top