associação pythonbrasil[11] django zope/plone planet Início Logado como (Entrar)

PythonNaoEJava

Python não é Java

(Esse texto é uma tradução de Python is not Java, de Phillip J. Eby. O texto não está licenciado sob a Creative Commons, pois está sujeito a restrições.)

Recentemente, dei uma olhada no código de uma aplicação GUI baseada em wxPython, com aproximadamente 45,5KLOC, sem contar as bibliotecas utilizadas (e.g. Twisted). O código foi escrito por programadores Java relativamente novos em Python e sofre de alguns problemas de performance (como 30 segundos de tempo de inicialização). Examinando o código, notei que eles fizeram um monte de coisas que fazem sentido em Java, mas que são terrivelmente inadequadas em Python. Não porque "Python é mais lento que Java", mas porque há maneiras mais fáceis de alcançar os mesmos objetivos em Python que sequer existem em Java.

Enfim, o triste é que essas pobres pessoas trabalharam muito, muito mais do que precisavam, para produzir muito mais código do que necessitavam escrever, que então tem o desempenho muito mais lento que o equivalente idiomático em Python teria. Alguns exemplos:

  • Um método estático em Java não se traduz para um método de classe em Python. Sim, claro, ele resulta mais ou menos no mesmo efeito, mas o objetivo do método de classe é, de fato, fazer coisas que normalmente sequer são possíveis em Java (como herdar um construtor não-padrão). A tradução idiomática de um método estático de Java normalmente é uma função em um módulo, não um método de classe ou método estático. (E campos estáticos finais devem ser traduzidos para constantes em um módulo).

    Não é tanto uma questão de performance: um programador Python que tenha de trabalhar num código com idiotismos de Java como esse provavelmente vai se irritar ao digitar Foo.Foo.someMethod quando deveria ser apenas Foo.someFunction. Entretanto, note que chamar um método de classe envolve uma alocação adicional de memória que chamar um método estático ou uma função não envolve.

    Ah, e todos aquelas cadeias de atributos Foo.Bar.Baz não são de graça, também. Em Java, aqueles "nomes pontuados" são resolvidos pelo compilador, então não importa quantos deles você tem em tempo de execução. Em Python, as resoluções ocorrem em tempo de execução, logo cada ponto conta. (Lembre-se que em Python "Plano é melhor que aninhado", embora isso esteja mais relacionado com "Legibilidade faz diferença" e "Simples é melhor que complexo" que com performance).

  • Precisa de um comando switch? A tradução para Python é uma tabela hash, não um monte de comandos if-then. Precisa de um monte de if-thens que não podem ser um comando switch em Java porque envolvem strings? Também é uma tabela hash. A implementação de dicionários de CPython usa uma das implementações de hash mais altamente otimizadas no universo conhecido. Nenhum código que você mesmo escreva irá funcionar melhor, a não ser que você seja um filho geneticamente aperfeiçoado do Guido, do Tim Peters e do Raymond Hettinger.

  • XML não é a resposta. XML não é nem mesmo a questão. Para parafrasear Jaime Zawinski sobre expressões regulares: "Algumas pessoas, quando confrontadas com um problema, pensam 'Já sei, vou usar XML'. Agora elas têm dois problemas".

  • É uma situação diferente daquela em Java, porque, comparado com código em Java, XML é ágil e flexível. Comparado com código em Python, XML é uma âncora de navio, uma bola de chumbo e uma corrente. Em Python, XML é algo que você usa para interoperabilidade, não em sua funcionalidade central, porque você simplesmente não precisa dele para isso. Em Java, XML pode ser sua salvação por permitir que você implemente linguagens de domínio específico e aumentar a flexibilidade da sua aplicação "sem codificar".

    Em Java, evitar codificar é uma vantagem porque codificar significa recompilar. Entretanto, em Python, freqüentemente, código é mais fácil de escrever que XML. E Python pode processar código muito, muito mais rapidamente do que seu código pode processar XML. (Não apenas isso, mas você tem de escrever código para processar XML, enquanto o próprio Python está escrito para você).

    Se você é um programador Java, não confie em seus instintos sobre quando você deve usar XML como parte de sua aplicação central em Python. Se você não está implementando um padrão XML existente por razões de interoperabilidade, criando algum tipo de formato de importação e exportação ou criando algum tipo de editor de XML ou ferramenta de processamento de XML, então "Apenas Não Faça Isto". De maneira alguma. Jamais. Nem mesmo apenas essa vez. Nem sequer pense sobre isso. Largue esse schema e mãos ao alto, agora! Se sua aplicação ou plataforma será utilizada por programadores Python, eles irão agradecer a você por não adicionar o fardo de utilizar XML em suas cargas de trabalho.

  • (A única exceção a isso é se seu público-alvo precisa mesmo, mesmo, de XML por alguma razão estranha. Por exemplo, eles se recusam a aprender Python e apenas irão pagá-lo se você usar XML, ou se você planeja dar-lhes uma GUI legal para editar o XML, e a GUI em questão é algo que alguma outra pessoa escreveu para editar XML e você pode usá-la de graça. Há também outras razões arquiteturais muito raras para utilizar XML. Acredite-me, elas não se aplicam à sua aplicação. Em caso de dúvida, explique seu caso de uso de XML para um desenvolvedor Python experiente. Ou, se você tem casca grossa e não se importa em ser motivo de risadas, tente explicar para um programador Lisp por que sua aplicação precisa de XML!).
  • Getters e setters são maus. Maus, eu disse maus! Objetos em Python não são Java beans. Não escreva getters e setters. É para isso que existe o built-in property. E não ache que isso significa que você deva escrever getters e setters, e então empacotá-los com property. Isso significa: até que você prove que você precisa de algo mais que um simples atributo de classe, você não não deve escrever getters e setters. Eles são um desperdício de tempo de CPU, mas, mais importante, eles são um desperdício do tempo do programador. Não somente para pessoas escrevendo código e testes, mas para pessoas que tenham de lê-los e entendê-los também.

    Em Java, você tem de usar getters e setters porque usar campos públicos não te dá a oportunidade de voltar atrás e mudar de idéia para usar getters e setters. Logo, em Java você pode tirar essa tarefa do caminho de uma vez. Em Python, isso seria tolice porque você pode começar com um atributo normal e mudar de idéia a qualquer momento, sem afetar quaisquer clientes da classe. Portanto, não escreva getters e setters.

  • Duplicação de código é, com muita freqüência, um mal necessário em Java, onde você tem de freqüentemente escrever o mesmo método várias e várias vezes com variações menores (usualmente devido a restrições da tipagem estática). Não é necessário nem desejável fazer isso em Python (exceto em certos casos raros de escrita inline de funções de desempenho crítico). Se você se percebe escrevendo a mesma função várias e várias vezes com variações menores, é hora de aprender sobre sobre fechamentos (closures). Eles não são tão assustadores assim.

  • Eis o que você vai fazer. Você escreve uma função que contém outra função. A função interna é um modelo para as funções que você está escrevendo várias e várias vezes, mas com variáveis para todas as coisas que mudam de uma função para outra. A função externa recebe parâmetros que possuem os mesmos nomes das variáveis, e retorna a função interna.

  • Então, em cada lugar onde você estaria escrevendo ainda outra função, simplesmente chame a função externa e atribua o valor retornado ao nome que você quer dar à função "duplicada". Agora, se você precisa mudar a maneira como o padrão trabalha, você apenas tem de mudar isso em um lugar: no modelo.

  • Na aplicação/plataforma que examinei, apenas uma aplicação bastante trivial dessa técnica poderia ter cortado fora centenas de linhas de peso morto em código. De fato, dado que esse boilerplate em particular tem de ser usado por programadores desenvolvendo plugins para a plataforma, isso irá economizar muito, muito mais centenas de linhas de código de desenvolvedores terceiros enquanto simplifica o que esses desenvolvedores têm de aprender.

Essa é apenas a ponta do iceberg da migração de mentalidade Java->Python, e é mais ou menos tudo em que eu posso entrar agora sem me aprofundar em pontos específicos a aplicações. Essencialmente, se você já usa Java há algum tempo e é novo em Python, não acredite em seus instintos. Seus instintos estão sintonizados para Java, não Python. Dê um passo atrás e, acima de tudo, pare de escrever tanto código.

Para fazer isso, torne-se mais exigente com o Python. Finja que o Python é uma varinha mágica que irá miraculosamente fazer o que quer que você queira sem você precisar levantar um dedo. Pergunte "Como Python já resolve meu problema?" e "Que característica da linguagem Python mais lembra meu problema?". Você vai ficar absolutamente espantado sobre quão freqüentemente acontece de aquela coisa que você precisa já estar lá de alguma forma. De fato, esse fenômeno é tão comum, mesmo entre programadores Python experientes, que a comunidade Python tem um nome para isso. Eles chamam isso de "máquina do tempo do Guido", porque às vezes parece que essa é a única maneira dele ter podido saber o que nós precisávamos antes de nós mesmos sabermos.

Enfim, se você não se sente como se estivesse no mínimo dez vezes mais produtivo com Python que com Java, há boas chances de que você está se esquecendo de usar a máquina do tempo! (E se você sente falta de sua IDE para Java, considere a possibilidade de que isso ocorre porque seus programas em Python são muito mais complexos do que precisariam ser.)