sábado, 25 de abril de 2009

Filosofia do Python

Publicação original: http://python-history.blogspot.com/2009/01/pythons-design-philosophy.html
Autor original: Guido van Rossum

As próximas entradas nesse blog aprofundarão detalhes da história do Python. Entretanto, antes que eu o faça, gostaria de apresentar a linha filosófica que me ajudou a tomar decisões enquanto projetava e implementava Python.

Primeiro, Python fora originalmente concebida como um projeto experimental de uma pessoa - não havia orçamento oficial e eu desejava resultados rápidos, em parte porque assim poderia convencer a gerência a suportar o projeto (tarefa a qual obtive sucesso moderado). Isso me levou a algumas regras que economizam tempo:
  • Tome emprestadas idéias de qualquer lugar, desde que elas façam sentido.
  • "As coisas devem ser as mais simples possíveis, mas não mais simples." - Einstein
  • Faça uma única coisa bem (A "filosofia Unix").
  • Não se preocupe muito sobre desempenho -- planeje otimizar depois, quando necessário.
  • Não reme contra a maré -- siga o fluxo.
  • Não tente ser perfeccionista. "Bom o suficiente" frequentemente é isso.
  • (Portanto) Tudo bem economizar às vezes, principalmente se puder fazer corretamente mais tarde.
Outros princípios não tinham intenção de economizar tempo. Às vezes ocorria justamente o oposto:
  • A implementação de Python não deve estar atada a uma plataforma em particular. Tudo bem se determinada funcionalidade não estiver disponível sempre, mas o núcleo da linguagem deve funcionar em todo lugar.
  • Não incomode o usuário com detalhes que a máquina pode cuidar (nem sempre segui essa regra e algumas consequências desastrosas estão descritas em seções posteriores).
  • Suporte e encorage código independente de plataforma, mas não remova o acesso a propriedades ou capacidades da plataforma (isso é um contraste gritante em relação a Java).
  • Um sistema grande e complexo deveria ter vários níveis de extensibilidade. Esse fato maximiza a oportunidade para que usuários, sofisticados ou não, se ajudem.
  • Erros não devem ser fatais. Ou seja, códigos dos usuários devem ser capazes de se recuperar de condições de erro, desde que a máquina virtual permaneça funcional.
  • Por outro lado, erros não devem passar desapercebidos (esses dois últimos itens levaram ao uso de exceções durante a implementação).
  • Nunca um bug no código do usuário deve levar a comportamentos indefinidos no interpretador de Python; um core dump nunca é falha do usuário.
Finalmente, eu tive várias idéias sobre um bom projeto de linguagem, que fora vastamente enraizado em mim pelo grupo de ABC onde tive minha primeira experiência real com projeto e implementação de linguagem. Essas idéias são difíceis de expressar, já que basicamente são sobre elegância, simplicidade e legibilidade.

Embora eu vá discutir mais sobre influência da ABC posteriormente, gostaria de mencionar uma regra específica sobre legibilidade: caracteres de pontuação deveriam ser usados conservadoramente, alinhados com seu uso comum em inglês ou álgebra. Exceções são feitas quando uma notação particular já é tradicional em linguagens de programação, como "x*y" para multiplicação, "a[i]" para indexação de vetores, ou "x.foo" para seleção de atributo, mas Python não usa "$" para indicar variáveis, nem "!" para indicar operações com efeitos colaterais.

Tim Peters, um usuário de Python de longa data e que eventualmente tornou-se um dos mais prolíficos e tenazes desenvolvedores, capturou meu princípio de design não documentado no que ele chama "O Zen de Python."
Cito aqui em sua totalidade:

  • Belo é melhor que feio.
  • Explícito é melhor que implícito.
  • Simples é melhor que complexo.
  • Complexo é melhor que complicado.
  • Plano é melhor que aninhado.
  • Esparso é melhor que denso.
  • Legibilidade conta.
  • Casos especiais não são especiais o suficiente para violar as regras.
  • Embora praticidade vença pureza.
  • Erros não devem passar silenciosamente.
  • A não ser que sejam explicitamente silenciados.
  • Em caso de ambiguidade, resista à tentação de adivinhar.
  • Deve haver um - e somente um - jeito óbvio de fazer.
  • Embora tal jeito não seja tão óbvio no à primeira vista a não ser que você seja holandês.
  • Agora é melhor que nunca.
  • Embora nunca é frequentemente melhor que exatamente agora.
  • Se a implementação é difícil de explicar, a ideia é ruim.
  • Se a implementação é fácil de explicar, talvez a ideia seja boa.
  • Espaços de nomes são uma ideia estupenda - vamos fazer mais deles!
Embora minha experiência com ABC tenha fortemente influenciado Python, o grupo de ABC tinha alguns princípios de design que eram radicalmente diferentes dos princípios de Python. Em muitas maneiras, Python é uma fuga consciente destes:
  • O grupo ABC se empenhava pela perfeição. Por exemplo, eles usavam algoritmos para estrutura de dados baseadas em árvores que haviam sido demonstrados ótimos para entradas assintoticamente grandes (mas não eram tão boas para entradas pequenas).
  • O grupo ABC queria isolar o usuário, tão completamente quanto possível, do "grande e mal mundo dos computadores." Não apenas não deveria haver limites para faixa de valores de números, comprimento de cadeias de caracteres ou tamanho de coleções (a não ser quantidade de memória disponível), bem como os usuários não deveriam ser solicitados a lidar com arquivos, "salvamento" ou outros programas. ABC deveria ser a única ferramenta da qual eles precisariam. Esse desejo levou o grupo ABC a criar um ambiente de edição completo, único à ABC (havia uma forma de escapar do ambiente ABC, claro, mas foi sobretudo uma idéia posterior e não acessível diretamente a partir da linguagem.)
  • O grupo ABC assumia que os usuários não tinham experiência prévia com computadores (ou desejavam esquecê-la). Portanto, terminologia alternativa, mais amigável para iniciantes, foi introduzida em vez do jargão padrão de programação. Por exemplo, procedimentos eram chamados "how-tos" (NT: como fazer) e variáveis, "locations" (NT: locais).
  • O grupo ABC projetou ABC sem uma linha evolucionária em mente e sem esperar participação do usuário no projeto da linguagem. ABC foi criada como um sistema fechado, tão sem falhas quanto seus projetistas poderiam torná-la. Usuários não eram encorajados a ver os detalhes internos da implementação. Embora tenha se falado em abrir parte da implementação para usuários avançados em estágios posteriores do projeto, isso nunca foi feito.
De certa forma, a filosofia de projeto que usei quando criei Python é provavelmente uma das principais razões para seu sucesso estrondoso. Em vez de almejar pela perfeição, os primeiros usuários consideraram que ela era "boa o suficiente" para seus propósitos. À medida que a base de usuários cresceu, sugestões de melhorias foram gradualmente incorporadas à linguagem. Como veremos em seções futuras, muitas dessas melhorias involveram mudanças substanciais e reconstrução de partes importantes da linguagem. Ainda hoje, Python continua a evoluir.

quinta-feira, 23 de abril de 2009

Introdução e Visão Geral

Publicação original: http://python-history.blogspot.com/2009/01/introduction-and-overview.html
Autor original: Guido van Rossum

Introdução

Python é atualmente uma das mais populares linguagens dinâmicas de programação, junto a Perl, Tcl, PHP e a novata Ruby. Embora frequentemente vista como linguagem de "scripts", é, na verdade, uma linguagem de programação de propósito geral, na mesma linha de Lisp ou Smalltalk (assim como outras linguagens, por assim dizer).
Hoje, Python é usada para tudo, desde scripts simples de uso único a grandes e escaláveis servidores web que proveem serviço ininterrupto 24x7. É usada em GUI (interfaces gráficas de usuário) e programação para banco de dados, programação web tanto no lado cliente quanto servidor e teste de aplicações. É usada por cientistas escrevendo programas para os supercomputadores mais velozes e por crianças aprendendo a programar.
Neste blog, focarei na história de Python. Em particular, como Python foi desenvolvida, as grandes influências em seu design, erros cometidos, lições aprendidas e próximos passos para a linguagem.

Agradecimento: Estou em dívida com Dave Beazley por muitas das melhores idéias neste blog. (Para ler mais sobre as origens deste blog, veja meu outro blog.)


Uma visão geral do Python


Quando alguém é exposto pela primeira vez ao Python, geralmente a pessoa se sente atordoada pelo modo como código escrito em Python se parece, pelo menos superficialmente, com código escrito em outras linguagens convencionais como C ou Pascal. Isso não é acidente, a sintaxe do Python é fortemente influenciada por C. Por exemplo, muitas das palavras chave reservadas (if, else, while, for, etc.) são as mesmas em C, identificadores em Python seguem a mesma regra de nomenclatura que C e muitos dos operadores possuem o mesmo significado dos operadores em C.
É claro, Python obviamente não é C e uma das maiores áreas onde as linguagens diferem é no uso de indentação em vez de chaves para agrupamento de comandos. Por exemplo, em vez de escrever comandos em C como

if (a < b) {
    max = b;
} else {
    max = a;
}


Python simplesmente dispensa as chaves (além de ponto-e-vírgula ao fim dos comandos) e usa a seguinte estrutura

if a < b:
    max = b
else:
    max = a


Outra grande área onde Python difere de linguagens semelhantes a C reside o uso de tipagem dinâmica. Em C, variáveis devem ser declaradas explicitamente e atribuídas a certo tipo de dados, como int ou double. Essa informação é usada para realizar verificações estáticas em tempo de compilação bem como para alocação de memória usada para armazenar os valores das variáveis. Em Python, variáves simplesmente são nomes que se referem a objetos. Não há necessidade de declarar variáveis antes que elas sejam atribuídas e elas podem até mudar de tipo no meio do programa. Assim como outras linguagens dinâmicas, toda verificação de tipo é realizada em tempo de execução por um interpretador em vez de ser realizada durante uma fase separada de compilação.

Os tipos internos primitivos de Python incluem Booleanos, números (inteiros do tamanho da palavra da máquina, inteiros de precisão arbitrária, e números de ponto flutuante reais e complexos) e cadeias de caracteres (8 bits e Unicode). Todos são tipos imutáveis, o que significa que os valores são representados por objetos que não podem ser modificados após a criação. Tipos internos compostos incluem tuplas (vetores imutáveis), listas (vetores redimensionáveis) e dicionários (tabelas de espalhamento, ou hash).

Para fins de organização, Python suporta pacotes (grupos de módulos e/ou outros pacotes), módulos (códigos relacionados agrupados em um único arquivo), classes, métodos e funções. Para controle de fluxo, Python provê if/else, while e um comando for de alto nível que percorre objetos “iteráveis”. Para tratamento de erros, Python usa exceções (não-continuáveis). O comando raise lança uma exceção e os comandos try/except/finally especificam os tratamentos de exceção. Operações internas lançam exceções quando condições de erro são atingidas.

Em Python, todos os objetos nomeáveis são considerados de "primeira classe." Isso significa que funções, classes, métodos, módulos e todos outros objetos nomeados podem ser facilmente referenciados, inspecionados e alocados em várias estruturas de dados (por exemplo, listas ou dicionários) em tempo de execução. Por falar em objetos, Python também fornece suporte à programação orientada a objetos, incluindo classes definidas pelo usuário, herança e ligação de métodos em tempo de execução.

Python possui uma ampla biblioteca, o que é um dos principais motivos para sua popularidade. A biblioteca padrão possui mais de 100 módulos e está em evolução constante. Alguns desses módulos incluem expressões regulares, funções matemáticas, threads, interface com sistema operacional, programação em rede, protocolos para internet (HTTP, FTP, SMTP, etc), manipulação de e-mail, processamento de XML, processamento de HTML e um kit para interface gráfica de usuário (Tcl/Tk).

Além disso, há um amplo suprimento de módulos e pacotes de terceiros, a maioria dos quais também de código aberto. Dentre esses, pode-se encontrar frameworks para web (há muitos para serem listados!), mais kits de interface, bibliotecas numéricas eficientes (incluindo empacotadores para vários pacotes populares em Fortran), interface com bancos de dados relacionais (Oracle, MySQL e outros), SWIG (uma ferramente para disponibilizar bibliotecas arbitrárias em C++ como módulos Python) e muito mais.

Um tópico atraente de Python (e outras linguagens dinâmicas por assim dizer) é o fato de que tarefas aparentemente complicadas podem ser frequentemente expressas com pouco código. Como exemplo, este é um script simples em Python que baixa uma página da web, a examina em busca de URLs e imprime as 10 primeiras referências.

# Examina a página web procurando por referências a URLs

import re
import urllib

regex = re.compile(r'href="([^"]+)"')

def matcher(url, max=10):
    "Imprime as primeiras referências a URLs em uma URL fornecida."
    data = urllib.urlopen(url).read()
    hits = regex.findall(data)
    for hit in hits[:max]:
        print urllib.basejoin(url, hit)

matcher("http://python.org")


Esse programa pode ser modificado facilmente para se criar um indexador web e, de fato, Scott Hassan me disse que escrevera o primeiro indexador do Google em Python. Hoje, Google emprega milhões de linhas de código em Python para gerenciar vários aspectos de suas operações, desde automação a gerenciamento de propagandas. (Aviso legal: atualmente sou um funcionário do Google.)

Debaixo dos panos, Python tipicamente é implementado usando uma combinação de compilador para bytecode e um interpretador. A compilação é executada implicitamente assim que módulos são carregados e várias primitivas requerem que o compilador esteja disponível em tempo de execução.
Embora a implementação de-facto seja escrita em C e esteja disponível para toda plataforma de hardware/software imaginável, várias outras implementações tornaram-se populares. Jython é uma versão que roda sobre uma máquina virtual Java e apresenta forte integração com Java. IronPython é uma versão para a plataforma Microsoft.NET e apresenta integração similar com linguagens rodando sobre .NET. PyPy é um compilador/interpretador otimizado escrito em Python (ainda um projeto de pesquisa sendo desenvolvido sob financiamento da União Européia). Também há o Stackless Python, uma variação da implementação em C que reduz a dependência na pilha para chamada de funções em C, para permitir co-rotinas, continuações e microthreads.

[Editado: adicionada uma frase que não foi traduzida. (2013-03-20)]