Recuo em Python - Opção de Solução

Na grande maioria dos idiomas, se todo o recuo for removido em todo o código-fonte do programa e for aplicado o autoformato, o programa permanecerá totalmente operacional e, ao mesmo tempo, será projetado no mesmo estilo.

Parece que, no caso de Python, essa operação não é possível.

Pelo menos, não consegui encontrar em nenhum lugar como detectar instantaneamente recuos deslocados aleatoriamente no Python. Eu mesmo tive que resolver esse problema.


Introdução


Caro leitor!
Se a afirmação estiver próxima de você:
1) Essa programação é uma arte.
2) Ao programar em qualquer idioma, você precisa aproveitar ao máximo o poder e a diversidade desse idioma para minimizar o código-fonte.
3) Ao programar, você precisa mostrar seu alto nível no código fonte do programa, para que ninguém possa dizer sobre o seu programa que ele é "burro".

Se pelo menos um (!) Dos pontos acima estiver perto de você, não leia este artigo! Por favor, não perca seu tempo com isso.
Falará sobre um momento completamente absurdo e absurdo de programação.

Caro leitor!
Se a declaração já estiver perto de você:
1) Que a programação é um trabalho rotineiro e bastante monótono, como cavar uma vala sem fim.
2) Que, ao programar em qualquer idioma, você precisa usar um determinado conjunto mínimo de comandos de idioma (possivelmente descartando a maioria de seus comandos) para que mesmo um programador júnior possa facilmente descobrir seu programa!
3) Que ao programar seu programa deve ser até certo ponto "burro". Para que depois de implementado, você possa iniciar um novo projeto e colocar calmamente o programador júnior que participou do projeto para apoiá-lo e aperfeiçoá-lo sob os novos e pequenos requisitos regulares do cliente.

Se todas essas três afirmações acima são verdadeiras para você, então talvez você tenha um problema cuja solução eu quero oferecer.

As principais desvantagens do Python:

1) O Python "não é minimizado" no uso de recursos e seus dados e, portanto, não é adequado para escrever programas que exijam o uso de recursos, como aplicativos móveis, programas de baixo nível (drivers, programas residentes, etc.) .) etc.

2) Python é lento e de thread único (GIL - Global Interpreter Lock).

3) No Python, os blocos de programa são baseados SOMENTE (!) Na indentação. Por causa disso:

  • a “legibilidade” dos programas diminui (veja abaixo);
  • a formatação automática completa do texto de origem é impossível;
  • existe a probabilidade de um erro ocorrer com um deslocamento acidental e despercebido de recuos, o que às vezes é muito difícil de encontrar e corrigir.

A primeira desvantagem do Python é difícil de atenuar, e aqui apenas há uma limitação no escopo de seu uso. Mas este é um momento natural, porque é impossível criar uma linguagem que seja mais eficaz em todas as áreas das tarefas.

A segunda desvantagem do Python é que ele possui excelente interoperabilidade bidirecional com o C / C ++.

Muitas vezes, um projeto bem-sucedido está se desenvolvendo rapidamente. E, a princípio, não há requisitos de alto desempenho e, no Python, pequenas inserções no C / C ++ são usadas, se necessário.
Porém, à medida que o projeto se desenvolve e se expande, os requisitos de desempenho aumentam de acordo, e o Python, cada vez mais, começa a cumprir as funções da linguagem chamada do C / C ++. Ao mesmo tempo, o papel do próprio Python não diminui, pois ao programar seções que não exigem alta velocidade de execução (e geralmente existem muitas delas em grandes projetos), o Python é uma ferramenta mais conveniente que o C / C ++.

E para a terceira desvantagem do Python, eu gostaria de oferecer minha própria solução.

Todos vocês sabem que, para a grande maioria dos idiomas, o formato automático do texto de origem é muito usado.

Essa. independentemente do recuo de um programa escrito nesse idioma, quando você iniciar o autoformato, todo o recuo será trazido para sua forma padrão. Para Python, isso parece impossível.

Qualquer programador que tenha escrito projetos em vários milhares de linhas da linguagem sabe que o processo de desenvolvimento não está apenas inventando a próxima parte do programa e preenchendo-a, mas movendo constantemente as seções do código para o subprograma, agora entre os blocos do programa, depois para os módulos externos comuns, etc. P.

Além disso, na prática, os usuários / clientes que já estão no estágio inicial, tendo trabalhado com o primeiro esboço do programa, começam a mudar e a completar as tarefas do projeto final, o que leva a um forte ajuste do código-fonte.

E então, no Python, no caso de uma alteração significativa em dezenas de partes do Programa de outra pessoa (!) (Ou no seu, mas que você nem lembra), vale a pena pegar acidentalmente um pedaço extra de código pertencente a outro bloco ao transferir um bloco, o programa pode permanecer totalmente operacional, mas o algoritmo de seu trabalho mudará (leia-se "o programa começará a funcionar incorretamente"), e encontrar o local de um erro desse tipo no programa de outra pessoa e, em seguida, restaurar corretamente o recuo às vezes é muito difícil!

Nesse caso, é claro que você pode olhar o texto de origem (antes das alterações), mas se você já fez muitas correções neste local, terá que "desenrolar" toda essa cadeia de correções.

Resolvendo o problema de indentação em Python


A indentação em Python é formada pelos seguintes comandos:

- class
- def

- for
- while

- if

- try

- with

E para remover a dependência do recuo, para cada um desses comandos, decidi estabelecer uma regra para usar o comando "final", que definitivamente fechará o bloco de comandos (recuo).

Comandos de classe e def


Para comandos class / def, geralmente não há problema em concluir o bloco de indentação, pois o bloco é fechado com o novo comando class / def.

O único caso é a presença de um ou mais subprogramas declarados dentro de outro subprograma / método.

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

Então, se você acidentalmente mudar o bloco de instruções do último subprograma interno, ele será mesclado com os comandos do subprograma / método no qual esse subprograma interno é declarado.

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

Nesse caso, no final dessa rotina / método interno, basta colocar “return”, o que indicará claramente o final do bloco de seus comandos.

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

Os comandos for e while


No final das instruções "for" e "while", é necessário colocar "continue".

Essa. o comando ficará assim:

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

e

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

Por exemplo:
        ...  ...

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

            ...  for  ...

            ...  for  ...

        ...  ...

A exclusão acidental da indentação nos últimos comandos do bloco "for" não leva a um erro de execução do programa, mas leva a resultados errados! E é muito difícil encontrar essa falha se você não conhece o algoritmo do programa (por exemplo, se é o programa de um colega aposentado)!

Aqui está como:
        ...  ...

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

        ...  for  ...

        ...  for  ...

        ...  ...

E no exemplo abaixo, a exclusão acidental do recuo gera um erro imediatamente:
        ...  ...

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

            ...  for  ...

            ...  for  ...

            continue

        ...  ...

Comando if


No final da instrução "if", você precisa colocar o comando "elif 0: pass" e, em vez de "else", usar o comando "elif 1:".

Essa. para "if" haverá um bloco completo de comandos:

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

Por exemplo:
        ...  ...

        if  result != -1 :

            ...  if ...

            ...  if ...

            ...  if ...

        elif 0: pass

        ...  ...

Se você fizer como mostrado acima, no bloco de comando “if ... elif 0: pass”, o recuo gerará um erro de inicialização.

Sem “elif 0: pass”, se os recuos nas últimas linhas do bloco “if” forem excluídos acidentalmente, você primeiro procurará o local que causou o programa inesperadamente começar a funcionar incorretamente e depois pensará sobre quais recuos devem estar no bloco e quais - não.
        ...  ...

        if  result != -1 :

            ...  if ...

        ...  if ...

        ...  if ...

        ...  ...

Por que outro motivo, na minha opinião, é aconselhável fechar os blocos de comandos criados pelos operadores "for",
"while", "if", etc. ...

porque quando você olha para uma seção de código onde há uma grande diferença no nível de
indentação entre o final da corrente bloco e no início do próximo, muitas vezes você não consegue mais entender qual recuo pertence a quê.

Em seguida, as construções com “continue” e “elif 0: pass”, além de proteger contra exclusão acidental, também permitirão indicar em qual bloco você começou e escrever um comentário .

Por exemplo, você vê o fim de um bloco grande:

                            ...  ...

                            ...  ...

                            ...  ...

                            ...  ...

                        ...  ...

                        ...  ...

                        ...  ...

                        ...  ...

    elif result == 1 :

        ...  ...

        ...  ...

        ...  ...

        ...  ...

E é difícil lembrar o que significa cada nível de indentação.

Mas é muito mais fácil quando se parece com isso:

                            ...  ...

                            ...  ...

                            ...  ...

                            ...  ...

                            continue    #   b'\\r\\n'   

                        ...  ...

                        ...  ...

                        ...  ...

                        ...  ...

                    elif 0: pass     #  " "  " "

                elif 0: pass         #   . - 

                continue             #    

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

        ...  ...

        ...  ...

        ...  ...

        ...  ...

Tente o comando


Existe uma analogia completa com "se".

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

O único problema é o finalmente: comando . Depois disso, você não poderá mais colocar nenhum comando do bloco de teste atual.

Portanto, se houver necessidade de usá-lo, para preservar a possibilidade de formatar automaticamente e proteger contra a exclusão acidental de recuos, é necessário remover o bloco de comando inteiro após "finalmente:" no subprograma local (ou seja, declare-o como um subprograma no subprograma atual).

Essa. o texto com "finalmente:" ficará assim:

    def my_ppg():
        ...
        return

    ...

    finally:
        my_ppg()

    ...

Nesse caso, você também pode aplicar a formatação automática com segurança e não ter medo de
excluir recuos acidentalmente.

Comando "Com"


Não há comandos adicionais para "with" no Python que possam servir como o fim de um bloco. Portanto, a situação com é semelhante à situação com finalmente.
Essa. transferimos todos os comandos que são executados no bloco de instruções "with" para a sub-rotina local, ou ... Mas então vou dizer uma coisa terrivelmente blasfema: "... ou você não precisa usá-lo".

O fato é que “with”, por um lado, é apenas um “invólucro” para os comandos existentes do Python (ou seja, você sempre pode substituí-lo por um conjunto semelhante de comandos); por outro lado, a prática mostrou que para programadores juniores esse contexto O gerente é difícil para o desenvolvimento completo. E, portanto, se você deseja que um programador júnior acompanhe calmamente o projeto implementado depois de você, não precisará usar equipes no projeto que impeçam seu trabalho.

Conclusão



Eu acho que você já entendeu que, se você escrever um programa em Python usando ANYWHERE (!) Das técnicas acima para criar blocos de indentação, é muito fácil escrever um programa desse tipo, mesmo que você incline ou remova completamente os recuos nele, porque para todos os blocos de comando, existe um começo e um fim do bloco, independente do recuo.

Agora, com um sorriso, colocamos a pergunta da seguinte forma: “Quais são as desvantagens do Python se você formatar corretamente os blocos de indentação, interagir com C / C ++, se necessário, e não usar o Python em aplicativos móveis e críticos para recursos?”

Resposta: “Apenas pequenas falhas. Essa. em geral - não. "

E com essa formulação da questão, podemos apenas aproveitar as principais vantagens do Python.

  1. Simplicidade.
  2. Ciclo mínimo de teste de sites: gravado-lançado-verificado
  3. Bibliotecas de poder / frameworks para Python são "para todos os gostos e cores".

Essas três vantagens juntas fornecem, na minha opinião, uma versão quase perfeita da linguagem (não esqueça que isso está sujeito apenas às condições especificadas na pergunta acima!).

All Articles