Pregunta

Existen herramientas de análisis estático para Python , pero las comprobaciones de tiempo de compilación tienden a ser diametralmente opuestas al enlace en tiempo de ejecución filosofía que Python abraza. Es posible envolver el intérprete estándar de Python con una herramienta de análisis estático para aplicar alguna " use restricciones estrictas como las de " pero no vemos una adopción generalizada de tal cosa.

¿Hay algo acerca de Python que hace que "usar estrictamente" comportamiento innecesario o especialmente indeseable?

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

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

Nota: El intérprete-envoltorio de Python no necesita requerir " usar restricciones estrictas como "- podría usar un pseudo-pragma similar a " use estricto " Eso sería ignorado por el intérprete normal. No estoy hablando de agregar una función de nivel de idioma.


Actualización: Explicando qué " uso estricto " lo hace en Perl por comentarios. (El enlace a los documentos oficiales se encuentra en el primer párrafo).

El " uso estricto " La directiva tiene tres componentes distintos, de los cuales solo dos son realmente interesantes:

  • usa variables estrictas: comprueba estáticamente el uso de variables con ámbito léxico en su programa. (Tenga en cuenta que, en Python, básicamente hay solo el alcance global y el alcance local ). Muchos linters de Python comprueban 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 advierte sobre cosas que parecen estar mal en ese sentido hasta que les dice que se callen; es decir

    FOO = 12
    foo += 3
    

    Si no estás haciendo nada sofisticado con tus espacios de nombres, esto puede ser útil para verificar errores tipográficos.

  • usa referencias estrictas: evita la desreferencia simbólica del espacio de nombres. El análogo más cercano de Python está utilizando localess () y globals () para realizar enlaces simbólicos y buscar identificadores.

  • usa subs estrictos: No hay análogo real en Python.

¿Fue útil?

Solución

" la filosofía de enlace en tiempo de ejecución que Python adopta ... hace que el uso estricto de " comportamiento innecesario [y] especialmente indeseable "

Muy buen resumen. Gracias.

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


Editar

" Estoy pidiendo que analicemos por qué no lo necesitamos y, en consecuencia, por qué los programadores de Perl piensan que sí lo necesitan. "

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

Sin embargo, dado que te tomaste el tiempo de hacer la pregunta nuevamente, te proporcionaré más evidencia de la respuesta que ya diste.

Escribo Java casi tanto como escribo Python. La comprobación de tipo estático de Java no evita problemas de lógica; no facilita cumplir con los requisitos de desempeño; no ayuda a cumplir con los casos de uso. Ni siquiera reduce el volumen de las pruebas unitarias.

Si bien la comprobación de tipos estáticos detecta el uso indebido ocasional de un método, esto lo 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 digo que se encuentren tipos incorrectos con muchas pruebas unitarias inteligentes, digo que la mayoría de los problemas de tipos incorrectos se encuentran a través de excepciones no manejadas en las que la cosa simplemente no se ejecutará lo suficiente como para 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 beneficio económico. No me hace más capaz de resolver los problemas reales que las personas reales tienen con sus datos reales.

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

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

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

¿Cómo puedo representar un 'Enum' en Python? : esta es una súplica para algún tipo de tipo de dominio limitado. Una clase con valores de nivel de clase prácticamente hace ese trabajo. " ¿Qué pasa si alguien cambia la tarea? " ;. Fácil de construir Anule __set__ para generar una excepción. Sí, la comprobación estática puede detectar esto. No, no sucede en la práctica que alguien se confunda sobre una constante y una variable enum; y cuando lo hacen, es fácil de detectar en el tiempo de ejecución. "Qué pasa si la lógica nunca se ejecuta". Bueno, eso es un diseño pobre y una prueba de unidad pobre. Lanzar un error de compilación y poner en una lógica incorrecta que nunca se probó no es mejor que lo que sucede en un lenguaje dinámico cuando nunca se prueba.

Expresiones del generador frente a la comprensión de la lista : la comprobación estática no ayuda a resolver esta pregunta.

¿Por qué 1 +++ 2 = 3? - estático la comprobación 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 es igual de legal. E igual de confuso.

Lista de cambios de listas reflejados inesperadamente en sublistas - - 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.

Otros consejos

Bueno, no soy un gran 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'.

Las variables estrictas (una de las opciones para estricto en Perl, 'usar estricto' las activa todas a la vez) en Perl requiere que todas las variables se declaren antes de usarse. 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 conozco una forma de hacer 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 en tiempo de ejecución que strict_iS_good no está definido. Pero solo cuando se ejecuta el código. Si su conjunto de pruebas no tiene una cobertura del 100%, puede enviar fácilmente este error.

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 de maneras que pueden ser difíciles de rastrear.

Entonces, para reiterar, Python podría usar un pragma 'estricto' para activar las comprobaciones de tiempo de compilación para las cosas que se pueden verificar en tiempo de compilación. No puedo pensar en ninguna otra verificación para agregar, pero un mejor programador de Python probablemente podría pensar en algunas.

Nota Me concentro en el efecto pragmático de las variables estrictas en Perl, y paso por alto algunos de los detalles. Si realmente desea conocer todos los detalles, consulte el perldoc para estricto .

Actualización: respuestas a algunos comentarios

Jason Baker : los comprobadores estáticos como pylint son útiles. Pero representan un paso adicional que puede ser y, a menudo, se omite. La creación de algunas comprobaciones básicas en el compilador garantiza que estas comprobaciones se realicen de forma coherente. Si estos controles son controlables por un pragma, incluso la objeción relacionada con el costo de los controles se vuelve discutible.

popcnt : Sé que Python generará una excepción de tiempo de ejecución. Yo dije lo mismo. Abogo por el tiempo de compilación comprobando cuando sea posible. Vuelve a leer la publicación.

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

Sin embargo, esto no significa que no se deba realizar ninguna comprobació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é clase de errores detectarán. Como dije, soy muy inexperto con Python.

Estos programas de análisis estático son útiles. Sin embargo, creo que a menos que dupliquen las capacidades del compilador, el compilador siempre estará en condiciones de "saber". más sobre el programa que cualquier comprobador 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 le gusta Perl, puede ejecutar código en tiempo de compilación), entonces el analizador estático debe acercarse a la complejidad del compilador / intérprete para hacer el análisis.

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

Entiendo que Python no tiene pragmas y no puede ejecutar código arbitrario en el momento de la compilación. Entonces, a menos que esté equivocado o se agreguen estas funciones, un analizador 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 bajar 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 tiene cuidado, puede terminar como Perl, y luego "solo Python puede analizar Python". Un futuro que no me gustaría ver.

Tal vez un interruptor 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 fallar con el comportamiento de compilación como Perl. Tengo la corazonada de que esta es una decisión de diseño cuidadosamente considerada, y puedo ver la sabiduría en La extrema flexibilidad de Perl en el momento de la compilación es, en mi humilde opinión, una gran fortaleza y una terrible debilidad del lenguaje; también veo la sabiduría en este enfoque.

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 bien definida que la Perl histórica; el tipo de cosas que & # 8216; referencias estrictas & # 8217; y & # 8216; subs estrictos & # 8217; prohibir nunca ha existido en Python.

& # 8216; vars estrictos & # 8217; está destinado principalmente a evitar que las referencias tipográficas y las perdidas & # 8216; my & # 8217; s generen globales accidentales (bueno, paquete de variables en términos de Perl). Esto no puede suceder en Python, ya que las asignaciones simples se asignan de forma predeterminada a la declaración local, y los símbolos no asignados descubren una excepción.

(Todavía existe el caso en que los usuarios intentan accidentalmente escribir en un global sin declararlo con una declaración & # 8216; global & # 8217; causando un error local accidental o, más a menudo, UnboundLocalError. Esto tiende a se aprende con bastante rapidez, pero es un caso discutible en el que tener que declarar a sus locales podría ayudar. Aunque pocos programadores experimentados de Python aceptarían la carga de legibilidad).

Otros cambios de idioma y biblioteca que no involucran sintaxis se manejan a través del sistema advertencias .

Creo que hay cierta confusión en cuanto a lo que " uso estricto " lo hace, por 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 anteriormente, este tipo de comprobaciones no protegen contra errores lógicos, no reducen la cantidad de pruebas unitarias que necesita escribir y tampoco somos grandes fanáticos de la programación de esclavitud.

Aquí hay una lista de lo que "utiliza estricto" hace:

  1. El uso de referencias simbólicas es un error en tiempo de ejecución. Esto evita que te vuelvas loco (pero a veces cosas útiles como)

    $ var = 'foo';

    $ foo = 'bar';

    print $$ var; # esto contendría el contenido de $ foo a menos que se ejecute bajo estricto

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

  3. Todas las palabras peladas se consideran errores de sintaxis en tiempo de compilación. Las palabras desnudas son palabras que no se han declarado como símbolos o subrutinas. Esto es principalmente para prohibir algo que se hizo históricamente pero que se considera un error.

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

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

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

  

Existen herramientas de análisis estático 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 adopta Python.

Lo que 'uso estricto' proporciona en Perl es la capacidad de garantizar que un error de ortografía o el nombre de la variable se captura (generalmente) en tiempo de compilación. Esto mejora el código fiabilidad y acelera el desarrollo. Pero para hacer que tal cosa valga la pena, Necesitas declarar variables. Y el estilo Python parece desalentar eso.

Entonces, en Python, nunca descubres una variable mal escrita hasta que te das cuenta de que tiempo de ejecución que la asignación que usted pensó que hizo no se está realizando, o que una La expresión parece resolverse a un valor inesperado. Atrapar tales errores puede ser lleva mucho tiempo, especialmente a medida que los programas se hacen más grandes, y las personas se ven obligadas a mantener 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, en lugar de filosófico. ¿Cómo puede detectar tantos errores como sea posible tan pronto como sea posible y asegurarse de eliminarlos antes de lanzar el código a producción? Cada idioma parece tomar una estrategia particular y ejecutarse en función de lo que pensar es importante En un lenguaje como Perl, donde el enlace en tiempo de ejecución no es compatible, tiene sentido aprovechar el 'uso estricto' para facilitar el desarrollo.

Considero que el 'uso estricto' en Perl se parece más a un pragma como insinuó: cambia el comportamiento del compilador.

La filosofía del lenguaje Perl es diferente de la filosofía Python. Al igual que en, se te da más que suficiente cuerda para colgarte repetidamente, en Perl.

Larry Wall es grande en lingüística, por lo que tenemos de Perl lo que se conoce como el principio TIMTOWTDI (por ejemplo, tim-toe-dee ) contra el Zen de python:

  

Debe haber uno-- y preferiblemente   Sólo una forma obvia de hacerlo.

podría usar muy fácilmente pylint y PyChecker para crear su propio sabor de uso estricto para python (o algo similar a perl -cw * scriptname * ) pero Debido a las diferentes filosofías en el diseño del lenguaje, no lo encontrará ampliamente en la práctica.

Según su comentario al primer póster, está familiarizado con import this de python. Hay muchas cosas allí que ilustran por qué no ve un equivalente de use estricto en Python. Si meditas en el koan que se encuentra en el Zen de Python, puedes encontrar la iluminación por ti mismo. :)

Descubrí que solo me importa realmente 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.

Va ??en contra de la naturaleza dinámica de Python, y de vez en cuando tengo que agregar #IGNOREs, cuando mi código se vuelve inteligente sobre algo. Pero me parece que eso ocurre con poca frecuencia, por lo que estoy contento con él.

Pero pude ver la utilidad de algunas funcionalidades similares a pylint disponibles en forma de un indicador de línea de comandos. Algo así como el interruptor -3 de Python 2.6, que identifica puntos de incompatibilidad entre Python 2.xy 3.x código.

Es muy difícil escribir programas grandes sin 'uso estricto' en Perl. Sin 'uso estricto', si usa una variable nuevamente y la escribe incorrectamente al dejar una letra, el programa aún se ejecuta. Y sin casos de prueba para verificar sus resultados, nunca podrá encontrar tales errores. Puede llevar mucho tiempo descubrir por qué está obteniendo resultados incorrectos debido a este motivo.

Algunos de mis programas Perl constan de 5,000 líneas a 10,000 líneas de código divididas en docenas de módulos. Realmente no se 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 imponen " declaraciones de variables " ;.

Esta es la razón por la que Perl 5.12.x ahora tiene el "uso estricto" como comportamiento predeterminado. Puedes apagarlos.

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

Sólo una opinión ...

abcParsing

Perl es un lenguaje sin restricciones como decían :). Así que puedes usar la variable antes anunciada; Por ejemplo: si usa un nombre var " is_array " pero escribe " is_arrby " , el compilador no informará de errores sin " usar estricto " . Por lo tanto, cuando codifique un programa largo en perl, use mejor "use estricto" declaración. Por supuesto, menos de 50 líneas para ejecutar un script de una sola vez, no hay necesidad :)

Parece el ideal de "Pythonic" El código sirve para el mismo propósito que use estricto .

No tengo un fondo de Perl, pero por lo que sé, no hay ninguna función en Python que deba desactivarse para que su código sea "más confiable", así que en ese sentido, supongo que puede decir que es innecesario

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top