Sangría en Python - Opción de solución

En la gran mayoría de los idiomas, si se elimina toda la sangría en todo el código fuente del programa y luego se aplica el autoformato, el programa permanecerá completamente operativo y al mismo tiempo se diseñará con el mismo estilo.

Parecería que en el caso de Python, tal operación no es posible.

Al menos no pude encontrar en ningún lado cómo detectar instantáneamente sangrías de desplazamiento aleatorio en Python. Tuve que resolver este problema yo mismo.


Introducción


¡Querido lector!
Si la declaración es cercana a usted:
1) Que la programación es un arte elevado.
2) Que cuando se programa en cualquier lenguaje, necesita aprovechar al máximo el poder y la diversidad de este lenguaje para minimizar el código fuente.
3) Que al programar, debe mostrar su alto nivel en el código fuente del programa para que nadie pueda decir sobre su programa que es "tonto".

Si al menos uno (!) De los puntos anteriores está cerca de usted, ¡no lea este artículo! Por favor, no pierdas tu tiempo en ello.
Hablará de un momento de programación completamente descabellado y absurdo.

¡Querido lector!
Si la declaración ya está cerca de usted:
1) Que la programación es una rutina, un trabajo bastante monótono, como cavar una zanja sinuosa.
2) Que al programar en cualquier lenguaje, debe usar un cierto conjunto mínimo de comandos de lenguaje óptimos (posiblemente descartando la mayoría de sus comandos) para que incluso un programador junior pueda descifrar su programa fácilmente
3) Que al programar su programa debe ser hasta cierto punto "tonto". Para que después de implementarlo, pueda comenzar un nuevo proyecto y poner tranquilamente al programador junior que participó en el proyecto para que lo apoye y refine bajo los nuevos y pequeños requisitos regulares del cliente.

Si todas estas tres afirmaciones anteriores son ciertas para usted, entonces quizás tenga un problema, cuya solución quiero ofrecer.

Las principales desventajas de Python:

1) Python "no está minimizado" en el uso de recursos y sus datos y, por lo tanto, no es adecuado para escribir programas que requieren el uso de recursos, como aplicaciones móviles, programas de bajo nivel (controladores, programas residentes, etc.) .) etc.

2) Python es lento y de un solo subproceso (GIL - Global Interpreter Lock).

3) En Python, los bloques de programa se basan SOLAMENTE (!) En la sangría. Debido a esto:

  • la "legibilidad" de los programas disminuye (ver más abajo);
  • el autoformato completo del texto fuente es imposible;
  • existe la posibilidad de que ocurra un error con una compensación accidental y desapercibida de sangría, que a veces es muy difícil de encontrar y corregir.

El primer inconveniente de Python es difícil de suavizar, y aquí solo tiene una limitación en el alcance de su uso. Pero este es un momento natural, porque Es imposible encontrar un lenguaje que sea más efectivo en todas las áreas de las tareas.

El segundo inconveniente de Python es que tiene una excelente interoperabilidad bidireccional con C / C ++.

A menudo, un proyecto exitoso se desarrolla con bastante rapidez. Y al principio no hay requisitos de alto rendimiento, y en Python, se utilizan pequeñas inserciones en C / C ++ si es necesario.
Pero a medida que el proyecto se desarrolla y se expande, los requisitos de rendimiento aumentan en consecuencia, y Python cada vez más a menudo comienza a cumplir las funciones del lenguaje llamado desde C / C ++. Al mismo tiempo, el papel de Python en sí mismo no disminuye, ya que Cuando se programan secciones que no requieren una alta velocidad de ejecución (y generalmente hay muchas en proyectos grandes), Python es una herramienta más conveniente que C / C ++.

Y para el tercer inconveniente de Python, me gustaría ofrecer mi propia solución.

Todos saben que para la gran mayoría de los idiomas, el formato automático de texto fuente se usa con mucha frecuencia.

Aquellos. No importa qué sangría esté escrito un programa en este idioma, cuando comience a formatear automáticamente, toda la sangría se llevará a su forma estándar. Para Python, esto parece imposible.

Cualquier programador que haya escrito proyectos en varios miles de líneas del lenguaje sabe que el proceso de desarrollo no es solo inventar la siguiente parte del programa y completarlo, sino mover constantemente secciones del código al subprograma, ahora entre los bloques del programa, luego a módulos externos comunes, etc. pags.

Además, en la práctica, los usuarios / clientes que ya están en la etapa inicial, después de haber trabajado con el primer esquema del programa, comienzan a cambiar y complementar las tareas del proyecto final, lo que conduce a un fuerte ajuste del código fuente.

Y luego, en Python, en caso de un cambio significativo en docenas de piezas del Programa (!) De otra persona (o el suyo, pero que no recuerda en absoluto), vale la pena capturar accidentalmente una pieza adicional de código perteneciente a otro bloque al transferir un bloque, el programa puede permanecer completamente operativo, pero el algoritmo de su trabajo cambiará (lea "el programa comenzará a funcionar incorrectamente"), ¡y encontrar el lugar de tal error en el programa de otra persona y luego restaurar correctamente la sangría a veces es muy difícil!

En este caso, por supuesto, puede ver el texto fuente (antes de los cambios), pero si ya ha realizado muchas correcciones en este lugar, tendrá que "desenrollar" toda esta cadena de correcciones.

Resolviendo el problema de sangría en Python


La sangría en Python está formada por los siguientes comandos:

- class
- def

- for
- while

- if

- try

- with

Y para eliminar la dependencia de la sangría, para cada uno de estos comandos decidí hacer una regla para usar el comando "final", que definitivamente cerrará el bloque de comandos (sangría).

Comandos de clase y def


Para los comandos class / def, generalmente no hay problemas para completar el bloque de sangría, ya que el bloque se cierra con el nuevo comando class / def.

El único caso es la presencia de uno o más subprogramas declarados dentro de otro subprograma / método.

def ppg_1():
    def ppg_2():
        ...  ppg_2 ...
    def ppg_3():
        ...  ppg_3 ...
        ...  ppg_3 ...
        ...  ppg_3 ...
    ...  ppg_1 ...

Luego, si accidentalmente cambia el bloque de instrucciones del último subprograma interno, se fusionará con los comandos del subprograma / método en el que se declara este subprograma interno.

def ppg_1():
    def ppg_2():
        ...  ppg_2 ...
    def ppg_3():
        ...  ppg_3 ...
    ...  ppg_3 ...
    ...  ppg_3 ...
    ...  ppg_1 ...

En este caso, al final de esta rutina / método interno solo necesita poner "return", que indicará claramente el final del bloque de sus comandos.

def ppg_1():
    def ppg_2():
        ...  ppg_2 ...
    def ppg_3():
        ...  ppg_3 ...
        ...  ppg_3 ...
        ...  ppg_3 ...
        return
    ...  ppg_1 ...

Los comandos for y while


Al final de las declaraciones "para" y "mientras" debe poner "continuar".

Aquellos. el comando se verá así:

for  <...> :             #  
    ...  ....
    continue             #  

y

while  <...> :           #  
    ...  ....
    continue             #  

Por ejemplo:
        ...  ...

        for i in range(10):
            ...  for ...

            ...  for  ...

            ...  for  ...

        ...  ...

¡Eliminar accidentalmente la sangría en los últimos comandos del bloque "for" no conduce a un error de ejecución del programa, sino que conduce a resultados erróneos! ¡Y es muy difícil encontrar tal falla si no conoce el algoritmo del programa (por ejemplo, si es el programa de un colega que se retira)!

Así es cómo:
        ...  ...

        for i in range(10):
            ...  for ...

        ...  for  ...

        ...  for  ...

        ...  ...

Y en el ejemplo a continuación, eliminar accidentalmente la sangría arrojará inmediatamente un error:
        ...  ...

        for i in range(10):
            ...  for ...

            ...  for  ...

            ...  for  ...

            continue

        ...  ...

Si comando


Al final de la declaración "if", debe poner el comando "elif 0: pass" y, en lugar de "else", usar el comando "elif 1:".

Aquellos. para "if" habrá un bloque completo de comandos:

if <>                      #  
    ...  ....
elif <>
    ...  ....
elif 1:                    #  "else"
    ...  ....
elif 0: pass               #  

Por ejemplo:
        ...  ...

        if  result != -1 :

            ...  if ...

            ...  if ...

            ...  if ...

        elif 0: pass

        ...  ...

Si lo hace como se muestra arriba, en el bloque de comandos "if ... elif 0: pass", la sangría generará un error de inicio.

Sin "elif 0: pass", si las sangrías en las últimas líneas del bloque "if" se borran accidentalmente, primero buscará el lugar que provocó que el programa comience a funcionar incorrectamente y luego piense qué sangrías deberían estar en el bloque y cuáles. - No.
        ...  ...

        if  result != -1 :

            ...  if ...

        ...  if ...

        ...  if ...

        ...  ...

Por qué si no, en mi opinión, es recomendable cerrar los bloques de comandos creados por los operadores "para",
"mientras", "si", etc ...

Porque cuando miras una sección de código donde hay una gran diferencia en el nivel de
sangría entre el final de la corriente bloque y al comienzo del siguiente, a menudo ya no puedes entender qué sangría pertenece a qué.

Luego, las construcciones con “continuar” y “elif 0: pasar”, además de proteger contra la eliminación accidental, también le permitirán indicar con qué bloque comenzó y escribir un comentario al respecto.

Por ejemplo, ve el final de un bloque grande:

                            ...  ...

                            ...  ...

                            ...  ...

                            ...  ...

                        ...  ...

                        ...  ...

                        ...  ...

                        ...  ...

    elif result == 1 :

        ...  ...

        ...  ...

        ...  ...

        ...  ...

Y es difícil recordar qué significa cada nivel de sangría.

Pero es mucho más fácil cuando se ve así:

                            ...  ...

                            ...  ...

                            ...  ...

                            ...  ...

                            continue    #   b'\\r\\n'   

                        ...  ...

                        ...  ...

                        ...  ...

                        ...  ...

                    elif 0: pass     #  " "  " "

                elif 0: pass         #   . - 

                continue             #    

            continue                 #  .,  -  " "
                      
    elif result == 1 :

        ...  ...

        ...  ...

        ...  ...

        ...  ...

Probar comando


Hay una analogía completa con "si".

try:                   #  
    ...  ....
except <...>:
    ...  ....
except 1:              #  "else"
    ...  ....
except 0: pass         #  

El único problema es el finalmente: comando . Después de eso, ya no puede poner ninguno de los comandos del bloque de prueba actual.

Por lo tanto, si es necesario usarlo, para preservar la posibilidad de formatear automáticamente y proteger contra la eliminación accidental de sangrías, debe eliminar todo el bloque de comandos después de "finalmente:" en el subprograma local (es decir, declararlo como un subprograma dentro del subprograma actual).

Aquellos. el texto con "finalmente:" será así:

    def my_ppg():
        ...
        return

    ...

    finally:
        my_ppg()

    ...

En este caso, también puede aplicar de forma segura el autoformato y no tener miedo de
eliminar sangría accidentalmente.

Comando "Con"


No hay comandos adicionales para "con" en Python que puedan servir como el final de un bloque. Por lo tanto, la situación con es similar a la situación con finalmente.
Aquellos. o transferimos todos los comandos que se ejecutan en el bloque de instrucciones "con" a la subrutina local, o ... Pero entonces diré una cosa terriblemente blasfema: "... o simplemente nunca necesitas usarlo".

El hecho es que "con", por un lado, es solo un "envoltorio" para los comandos de Python existentes (es decir, siempre puede reemplazarlo con un conjunto similar de comandos), por otro lado, la práctica ha demostrado que para los programadores junior este contexto El gerente es difícil para el desarrollo completo. Y, por lo tanto, si desea que un programador junior acompañe con calma el proyecto implementado después de usted, entonces no necesita usar equipos en el proyecto que impidan su trabajo.

Conclusión



Creo que ya entendió que si escribe un programa en Python usando CUALQUIER LUGAR (!) De las técnicas anteriores para crear bloques de sangría, es bastante fácil escribir un FORMATO AUTOMÁTICO COMPLETO de este tipo, incluso si sesga o elimina completamente las sangrías en él, porque Para todos los bloques de comandos hay un principio y un final del bloque, independiente de la sangría.

Y ahora, con una sonrisa, planteamos la siguiente pregunta: "¿Cuáles son las desventajas de Python si formatea correctamente los bloques de sangría, si es necesario, interactúa con C / C ++ y no usa Python en aplicaciones móviles y de recursos críticos?"

Respuesta: “Solo fallas menores. Aquellos. en general, no.

Y con tal formulación de la pregunta, solo podemos disfrutar de las principales ventajas de Python.

  1. Sencillez.
  2. Ciclo mínimo de prueba de sitios: escrito-lanzado-verificado.
  3. Poder - las bibliotecas / frameworks para Python son "para todos los gustos y colores".

Estas tres ventajas juntas dan, en mi opinión, una versión casi perfecta del lenguaje (¡no olvide que esto solo está sujeto a las condiciones especificadas en la pregunta anterior!).

All Articles