python perl compiler-construction static-analysis use-strict

¿Existe la necesidad de un compilador Python "use strict"?



perl compiler-construction (12)

"La filosofía de vinculación en tiempo de ejecución que Python abarca ... hace que el comportamiento de" uso estricto "sea innecesario [y] especialmente indeseable"

Bastante buen resumen. Gracias.

Eso es esencialmente eso. Las herramientas de análisis estático no ayudan a Python lo suficiente como para valer la pena.

Editar

"Estoy pidiendo que hagamos una introspección sobre por qué no lo necesitamos y, en relación con esto, por qué los programadores de Perl creen que lo necesitan".

La razón por la cual es precisamente la razón por la que ya diste. No lo necesitamos porque no ayuda. Claramente, no te gusta esa respuesta, pero no hay mucho más que decir. La verificación del tiempo de compilación o precompilación simplemente no ayuda.

Sin embargo, dado que se tomó el tiempo para hacer nuevamente la pregunta, proporcionaré más pruebas de la respuesta que ya dio.

Escribo Java casi tanto como escribo Python. La comprobación de tipos estáticos de Java no previene ningún problema de lógica; no facilita el cumplimiento de los requisitos de rendimiento; no ayuda a cumplir los casos de uso. Ni siquiera reduce el volumen de las pruebas unitarias.

Si bien la comprobación de tipo estática detecta el uso indebido ocasional de un método, esto se descubre con la misma rapidez en Python. En Python lo encuentras en el tiempo de prueba de la unidad porque no se ejecutará. Nota: No estoy diciendo que se encuentren tipos incorrectos con muchas pruebas de unidades inteligentes, estoy diciendo que la mayoría de los problemas de tipo incorrecto se encuentran a través de excepciones no controladas donde simplemente no se ejecuta lo suficiente como para llegar a probar las afirmaciones.

La razón por la cual los Pythonistas no pierden el tiempo en la comprobación estática es simple. No lo necesitamos No ofrece ningún valor. Es un nivel de análisis que no tiene ningún beneficio económico. No me hace más capaz de resolver los problemas reales que las personas reales están teniendo con sus datos reales.

Mire las preguntas más populares de SO Python relacionadas con el lenguaje (no el dominio del problema o la biblioteca).

¿Hay alguna diferencia entre "foo is None" y "foo == None"? - == vs. is . Ninguna comprobación estática puede ayudar con esto. Además, vea ¿Hay alguna diferencia entre `==` y `is` en Python?

¿Qué hace ** (doble estrella) y * (estrella) para los parámetros? - *x da una lista, **x da un diccionario. Si no sabe esto, su programa fallece inmediatamente cuando intenta hacer algo inapropiado para esos tipos. "¿Qué pasa si tu programa nunca hace nada ''inapropiado''". Entonces tu programa funciona. ''dijo nuff.

¿Cómo puedo representar un ''Enum'' en Python? - este es un argumento para algún tipo de tipo de dominio limitado. Una clase con valores de nivel de clase hace más o menos ese trabajo. "¿Qué pasa si alguien cambia la tarea". Fácil de construir Anular __set__ para levantar una excepción. Sí, la comprobación estática podría detectar esto. No, en la práctica no sucede que alguien se confunde con una constante enum y una variable; y cuando lo hacen, es fácil de detectar en tiempo de ejecución. "¿Qué pasa si la lógica nunca se ejecuta". Bueno, eso es un diseño pobre y pruebas de unidades pobres. Lanzar un error de compilación y poner una lógica incorrecta que nunca se ha probado no es mejor que lo que sucede en un lenguaje dinámico cuando nunca se prueba.

Expresiones de generador vs. Comprensión de lista : la comprobación estática no ayuda a resolver esta pregunta.

¿Por qué 1 +++ 2 = 3? - la comprobación estática no detectaría esto. 1 +++ 2 en C es perfectamente legal a pesar de todas las comprobaciones del compilador. No es lo mismo en Python que en C, pero igual de legal. Y tan confuso.

Lista de cambios de listas reflejados en las sublistas inesperadamente : esto es completamente conceptual. La comprobación estática tampoco puede ayudar a resolver este problema. El equivalente de Java también se compilaría y se comportaría mal.

Existen herramientas de análisis estáticas para Python , pero las comprobaciones de tiempo de compilación tienden a ser diametralmente opuestas a la filosofía de enlace de tiempo de ejecución que Python adopta. Es posible ajustar el intérprete estándar de Python con una herramienta de análisis estático para aplicar algunas restricciones tipo " use strict ", pero no vemos una adopción generalizada de tal cosa.

¿Hay algo sobre Python que haga que el comportamiento de "uso estricto" sea innecesario o especialmente indeseable?

Alternativamente, ¿el comportamiento de "uso estricto" es innecesario en Perl, a pesar de su adopción generalizada?

Nota: Por "necesario" me refiero a "prácticamente necesario", no estrictamente necesario. Obviamente puedes escribir Perl sin "usar estricto", pero (por lo que he visto) la mayoría de los programadores de Perl lo usan.

Nota: El intérprete-envoltorio de Python no necesita restricciones de tipo "use strict"; podría usar un pseudo-pragma similar a "use strict" que el intérprete normal ignoraría. No estoy hablando de agregar una función de nivel de idioma.

Actualización: explicando qué hace "usar estricto" en Perl por comentarios. (El enlace a los documentos oficiales está en el primer párrafo).

La directiva "use strict" tiene tres componentes distintos, de los cuales solo dos son realmente interesantes:

  • use termines estrictos: comprueba de forma estática el uso de variables de alcance léxico en su programa. (Tenga en cuenta que, en Python, básicamente hay solo alcance global y alcance local ). Muchos linters de Python buscan este tipo de cosas. Dado que es el único análisis estático que pueden hacer, los linters suponen que usa un alcance léxico directo y le advierten sobre cosas que parecen incorrectas en ese sentido hasta que les dice que se callen; es decir

    FOO = 12 foo += 3

    Si no estás haciendo algo elegante con tus espacios de nombres, esto puede ser útil para detectar errores tipográficos.

  • utilice refs estrictos: evita la eliminación de referencias del espacio de nombres simbólico. El análogo más cercano de Python está usando locals() y globals() para hacer un enlace simbólico y búsqueda de identificador.

  • use sub estrictos: no hay ningún análogo real en Python.


Bueno, no soy muy programador de Python, pero diría que la respuesta es ''SÍ''.

Cualquier lenguaje dinámico que le permita crear una variable con cualquier nombre en cualquier momento, podría usar un pragma ''estricto''.

Los vars estrictos (una de las opciones para estricto en Perl, ''use strict'' los activa todos a la vez) en Perl requiere que todas las variables se declaren antes de que se utilicen. Lo que significa que este código:

my $strict_is_good = ''foo''; $strict_iS_good .= ''COMPILE TIME FATAL ERROR'';

Genera un error fatal en tiempo de compilación.

No sé de una manera de conseguir que Python rechace este código en tiempo de compilación:

strict_is_good = ''foo''; strict_iS_good += ''RUN TIME FATAL ERROR'';

Obtendrá una excepción de tiempo de strict_iS_good que strict_iS_good no está definido. Pero solo cuando el código se ejecuta. Si su suite de pruebas no tiene una cobertura del 100%, puede enviar este error fácilmente.

Cada vez que trabajo en un idioma que no tiene este comportamiento (PHP, por ejemplo), me pongo nervioso. No soy un mecanógrafo perfecto. Un error tipográfico simple, pero difícil de detectar, puede hacer que su código falle en formas que pueden ser difíciles de rastrear.

Por lo tanto, para reiterar, YES Python podría usar un pragma "estricto" para activar las comprobaciones de tiempo de compilación de las cosas que pueden verificarse en tiempo de compilación. No puedo pensar en otros controles para agregar, pero un mejor programador de Python probablemente podría pensar en algunos.

Tenga en cuenta que me concentro en el efecto pragmático de los vatic de stict en Perl, y estoy pasando por alto algunos de los detalles. Si realmente quieres saber todos los detalles, consulta el perldoc para obtener información estricta .

Actualización: respuestas a algunos comentarios

Jason Baker : las damas estáticas como la pildora son útiles. Pero representan un paso adicional que puede ser omitido. Crear algunas comprobaciones básicas en el compilador garantiza que estas comprobaciones se realizan de forma coherente. Si estos controles son controlables por un pragma, incluso la objeción relativa al costo de los cheques se convierte en discutible.

popcnt : Sé que python generará una excepción de tiempo de ejecución. Dije tanto. Abogo por el tiempo de compilación cuando sea posible. Por favor, vuelve a leer la publicación.

mpeters : ningún análisis informático del código puede encontrar todos los errores; esto equivale a resolver el problema de detención. Peor aún, para encontrar errores tipográficos en las asignaciones, su compilador necesitaría conocer sus intenciones y encontrar lugares donde sus intenciones difieran de su código. Esto es bastante claramente imposible.

Sin embargo, esto no significa que no se debe hacer ninguna verificación. Si hay clases de problemas que son fáciles de detectar, entonces tiene sentido atraparlos.

No estoy lo suficientemente familiarizado con pylint y pychecker para decir qué clases de errores detectarán. Como dije, soy muy inexperto con Python.

Estos programas de análisis estáticos son útiles. Sin embargo, creo que a menos que dupliquen las capacidades del compilador, el compilador siempre estará en posición de "saber" más sobre el programa que cualquier otro inspector estático. Parece un desperdicio no aprovechar esto para reducir los errores cuando sea posible.

Actualización 2:

cdleary - En teoría, estoy de acuerdo con usted, un analizador estático puede hacer cualquier validación que pueda hacer el compilador. Y en el caso de Python, debería ser suficiente.

Sin embargo, si su compilador es lo suficientemente complejo (especialmente si tiene muchos pragmas que cambian la forma en que se produce la compilación, o si, como Perl, puede ejecutar código en tiempo de compilación), el analizador estático debe aproximarse a la complejidad del compilador / intérprete. haz el analisis

Heh, toda esta charla de compiladores complejos y código de ejecución en tiempo de compilación muestra mi fondo de Perl.

Tengo entendido que Python no tiene pragmas y no puede ejecutar código arbitrario en tiempo de compilación. Entonces, a menos que esté equivocado o que estas características se agreguen, un analizador sintáctico relativamente simple en el analizador estático debería ser suficiente. Ciertamente sería útil forzar estos controles en cada ejecución. Por supuesto, la forma en que haría esto es con un pragma.

Una vez que agrega pragmas a la mezcla, ha comenzado a descender por una pendiente resbaladiza y la complejidad de su analizador debe crecer en proporción a la potencia y flexibilidad que proporciona en sus pragmas. Si no tienes cuidado, puedes terminar como Perl, y luego "solo Python puede analizar Python", un futuro que no me gustaría ver.

Tal vez un cambio de línea de comando sería una mejor manera de agregar análisis estático forzado;)

(De ninguna manera pretendo impugnar las capacidades de Python cuando digo que no puede funcionar con el comportamiento de tiempo de compilación como Perl. Tengo el presentimiento de que esta es una decisión de diseño cuidadosamente considerada, y puedo ver la sabiduría en ella. Perl''s la flexibilidad extrema en el momento de la compilación es, en mi humilde opinión, una gran fortaleza y una debilidad terrible del lenguaje; también veo la sabiduría en este enfoque).


Considero que el ''use strict'' en Perl es más parecido a un pragma como lo insinuó: cambia el comportamiento del compilador.

La filosofía del lenguaje Perl es diferente de la filosofía python. Como en, te dan cuerda más que suficiente para ahorcarte repetidas veces, en Perl.

Larry Wall es un gran lingüista, así que tenemos de Perl lo que se conoce como el principio TIMTOWTDI (digamos, tim-toe-dee ) vs. Zen de python:

Debería haber una, y preferiblemente solo una, forma obvia de hacerlo.

podrías usar fácilmente pylint y PyChecker para dar con tu propio estilo de use strict para python (o algo análogo a perl -cw *scriptname* ) pero debido a las diferentes filosofías en el diseño del lenguaje, no encontrarás esto en la práctica extensamente.

Según su comentario al primer póster, está familiarizado con la import this de Python. Hay muchas cosas que iluminan por qué no ves un use strict en Python. Si meditas en el koan encontrado en el Zen de Python, puedes encontrar la iluminación para ti. :)


Creo que hay algo de confusión, como el "uso estricto" de los comentarios que estoy viendo. No activa las comprobaciones de tipo de tiempo de compilación (para ser como Java). En ese sentido, los programadores de Perl están de acuerdo con los programadores de Python. Como dice S.Lott, estos tipos de controles no protegen contra errores de lógica, no reducen el número de pruebas de unidad que necesita escribir y tampoco somos grandes admiradores de la programación de bondage.

Aquí hay una lista de lo que hace "use strict":

  1. El uso de referencias simbólicas es un error en tiempo de ejecución. Esto le impide hacer locuras (pero a veces cosas útiles como)

    $var = ''foo'';

    $foo = ''bar'';

    print $$var; # this would contain the contents of $foo unless run under strict

  2. El uso de variables no declaradas es un error en tiempo de ejecución (esto significa que debe usar "mi", "nuestro" o "local" para declarar el alcance de su variable antes de usarla).

  3. Todas las palabras sin formato se consideran errores de sintaxis en tiempo de compilación. Las palabras clave son palabras que no han sido declaradas como símbolos o subrutinas. Esto es principalmente para declarar ilegal algo que históricamente se hizo, pero se considera que fue un error.


Descubrí que solo me importa detectar referencias a vars no declarados. Eclipse tiene integración de pylint a través de PyDev y, aunque pylint está lejos de ser perfecto, hace un trabajo razonable en eso.

En cierto modo va en contra de la naturaleza dinámica de Python, y tengo que agregar #IGNOREs de vez en cuando, cuando mi código se vuelve inteligente sobre algo. Pero creo que eso sucede con la suficiente frecuencia que estoy contento con eso.

Pero pude ver la utilidad de alguna funcionalidad parecida a la de una pila que está disponible en forma de un indicador de línea de comando. Algo así como el conmutador -3 de Python 2.6, que identifica los puntos de incompatibilidad entre el código de Python 2.xy 3.x.


Es muy difícil escribir programas grandes sin ''uso estricto'' en Perl. Sin ''use strict'', si usa una variable nuevamente y la deletrea mal dejando una letra, el programa aún se ejecuta. Y sin casos de prueba para verificar sus resultados, nunca puede encontrar tales errores. Puede llevar mucho tiempo encontrar por qué está obteniendo resultados incorrectos debido a esta razón.

Algunos de mis programas Perl consisten de 5,000 líneas a 10,000 líneas de código divididas en docenas de módulos. Uno realmente no puede hacer programación de producción sin ''uso estricto''. Nunca permitiría que el código de producción se instale en la fábrica con idiomas que no hagan cumplir las "declaraciones de variables".

Es por esto que Perl 5.12.x ahora tiene el ''uso estricto'' como el comportamiento predeterminado. Puedes apagarlos.

PHP me ha dado bastantes problemas debido a la no aplicación de declaración de variables. Por lo tanto, debe limitarse a pequeños programas con este idioma.

Solo una opinión ...

abcParsing


Esta respuesta original es correcta, pero quizás no explica la situación en un sentido práctico.

Existen herramientas de análisis estáticas para Python, pero las comprobaciones del tiempo de compilación tienden a ser> diametralmente opuestas a la filosofía de enlace en tiempo de ejecución que Python adopta.

Lo que ''use strict'' en Perl es la capacidad de asegurar que un nombre mal deletreado o variable (generalmente) sea capturado en tiempo de compilación. Esto mejora la fiabilidad del código y acelera el desarrollo. Pero para que tal cosa valga la pena, debes declarar las variables. Y el estilo de Python parece desalentar eso.

Por lo tanto, en Python, nunca se entera de una variable mal deletreada hasta que en el tiempo de ejecución se da cuenta de que no se está realizando la asignación que creía que había realizado, o que una expresión parece resolverse a un valor inesperado. Captar tales errores puede llevar mucho tiempo, especialmente a medida que los programas crecen y las personas se ven obligadas a mantener el código desarrollado por otros.

Java y C / C ++ van un paso más allá, con la verificación de tipos. La motivación es práctica, más que filosófica. ¿Cómo puede detectar tantos errores como sea posible tan pronto como sea posible, y asegúrese de eliminarlos todos antes de liberar el código a producción? Cada idioma parece tomar una estrategia particular y funcionar con ella, en función de lo que creen que es importante. En un lenguaje como Perl, donde no se admite el enlace en tiempo de ejecución, tiene sentido aprovechar el uso estricto para facilitar el desarrollo.


No tengo experiencia en Perl, pero por lo que sé, no hay ninguna función en Python que deba ser desactivada para que tu código sea "más confiable", así que en ese sentido, creo que puedes decir que es innecesario


Parece que el ideal del código "Pythonic" tiene muchas finalidades similares a las del use strict .


Perl es un lenguaje desenfrenado, como decían :). Entonces puedes usar la variable antes anunciada; Por ejemplo: si usa un nombre var "is_array" pero escribe "is_arrby", el compilador no informará el error sin "use strict". Entonces, cuando codifique el programa largo en perl, mejor use la declaración "use strict". Por supuesto, menos de 50 líneas para ejecutar una secuencia de comandos de tiempo, no hay necesidad :)


Python no tiene un verdadero alcance léxico, por lo que los vars estrictos no serían muy sensibles. No tiene referencias simbólicas AFAIK, por lo que no necesita refs estrictos. No tiene palabras ocultas, por lo que no necesita vars estrictos.

Para ser honesto, es solo el alcance léxico lo que extraño. Los otros dos consideraría verrugas en Perl.


Python tiene algo que puede cambiar la sintaxis del script:

from __future__ import print_function

y varias otras características futuras que tienen implicaciones de sintaxis. Es solo que la sintaxis de Python ha sido más estricta, más estable y más definida que la Perl histórica; el tipo de cosas que prohíben los ''estrictos refs'' y ''strict subs'' nunca han existido en Python.

''estrictos vars'' está destinado principalmente a detener referencias tipográficas y ''my''s'' omitidas para crear variables globales accidentales (bueno, variables de paquete en términos de Perl). Esto no puede suceder en Python ya que las asignaciones vacías se establecen por defecto en la declaración local, y los símbolos desnudos no asignados producen una excepción.

(Todavía existe el caso donde los usuarios accidentalmente intentan escribir a través de un global sin declararlo con una declaración ''global'', causando un local accidental o, más a menudo, un UnboundLocalError. Esto tiende a aprenderse con bastante rapidez, pero es un caso discutible en el que tener que declarar que los lugareños podrían ayudar. Aunque pocos programadores experimentados de Python aceptarían la carga de legibilidad).

Otros cambios de lenguaje y biblioteca que no implican sintaxis se manejan a través del sistema de warnings .