quarta-feira, 25 de janeiro de 2012

Como limpar o console do Python no Windows

Demonstrando Python no telão, muitas vezes é bom limpar o console, para começar uma nova parte da demonstração no topo da tela. No Linux e no OSX é fácil: CTRL-L. Mas no Windows isso não funciona. No DOS existe o comando cls, mas como acioná-lo a partir do Python de modo conveniente?

Pesquisando na Web, achei uma conversa no StackOverflow (que Allah o proteja sempre!). Lá tem várias respostas mas a mais legal é este pequeno script:
class cls(object):
    def __repr__(self):
        import os
        os.system('cls' if os.name == 'nt' else 'clear')
        return ''

cls = cls()

Como usar

Depois de salvar este código em um script cls.py, há três maneiras de usá-lo. A primeira e mais simples é invocar o Python assim:
C:\Users\Luciano> python -i cls.py
Desta forma o Python executa o script, definindo a classe cls e criando uma variável global com o mesmo nome. Para limpar o console, basta digitar no prompt do Python:
>>> cls
Os únicos inconvenientes da abordagem acima são ter que lembrar de invocar o Python com a opção -i cls.py e um pequeno detalhe: o cabeçalho que indica a versão do Python é omitido com esta opção, e isso pode confundir.

Instalar como script de inicialização

Se quiser usar o pseudo-comando cls toda vez que rodar o Python, você pode usar esta dica do tutorial do Python: crie uma variável de ambiente no Windows chamada PYTHONSTARTUP e coloque nela o caminho completo até o arquivo cls.py. No meu caso, salvei o arquivo no diretório onde o Python para Windows já traz alguns scripts, e o caminho ficou assim:
C:\Users\Luciano> echo %PYTHONSTARTUP%
C:\Python27\Scripts\cls.py
Feito isso, o script cls.py será executado toda vez que você rodar o Python em modo interativo (mas não quando executar algum script).
A terceira forma de instalar o comando cls seria usando um módulo de customização, como explicado no Tutorial, mas não achei prática esta alternativa no Windows porque o caminho onde eu teria que criar o módulo não existe e, mesmo se criado, é de difícil acesso no Windows 7 (fica num lugar bizarro que tem AppData\Roaming no caminho).

Como funciona

A graça do script cls.py está em usar o método __repr__ para executar uma chamada ao SO para limpar a tela. O __repr__ serve para produzir uma string que representa o objeto de forma precisa, e é o que o Python usa para mostrar o valor de qualquer expressão no console interativo.

Ao criar uma instância da classe cls e atribuir esta instância à variável global com o mesmo nome, toda vez que digitamos cls no prompt, para exibir o valor desta variável o Python executa repr(cls) e isso invoca o nosso método cls.__repr__(). Uma solução simples e inteligente, usando um pouco de conhecimento sobre o modelo de objetos da linguagem.

segunda-feira, 2 de janeiro de 2012

Python para quem sabe Python: relato das primeiras turmas

Em 15 novembro de 2011 lancei a oficina Python para quem sabe Python para compartilhar um pouco do que aprendi em 13 anos de uso desta linguagem. Duas semanas depois, começamos duas turmas, com 29 pessoas no total, uma aos sábados de manhã e outra 3ª e 5ª-feira à noite. Fiquei muito feliz de encontrar entre os participantes alguns ex-alunos de outros cursos, outros parceiros de projetos anteriores, amigos da comunidade Python e gente nova para mim, a maioria de outros estados (eu moro em São Paulo).

A idéia da oficina PPQSP é revelar em profundidade algumas das "armas secretas" de Python. Não são segredos de verdade, tudo está muito bem documentado, mas são recursos que muitos programadores não usam, usam sem entender, ou usam menos do que poderiam, porque são diferentes do que se encontra em Java, C#, PHP, Ruby etc.

Os principais temas foram:

Iteráveis, iteradores e geradores

O importante padrão de projeto Iterator tem suporte sintático nativo em Python desde o início, por isso temos há 20 anos o melhor comando for do mercado (ultimamente imitado por outras linguagens).

Mas o Guido não ficou por aí, e incorporou os conceitos de geradores (expressões e funções geradoras) e, a partir do Python 2.6, as classes abstratas Iterable e Iterator que formalizam e explicitam estas idéias. Com funções geradoras podemos implementar co-rotinas em Python, e isso tem o potencial de simplificar bastante a programação assíncrona usada em sistemas Web de alto desempenho.

Exploramos em profundidade iteradores e iteráveis, desde uma discussão do padrão de projeto clássico, até vários exemplos e exercícios que ilustram como ele é implementado de forma pythônica. Concluímos a oficina demonstrando uma aplicação de função geradora como co-rotina para simplificar a programação assíncrona com o framework Tornado. O exemplo final está no repositório do curso no Github.

Metaprogramação com atributos dinâmicos

Desde as funções básicas getattr e setattr, passando por propriedades (properties) e chegando até os descritores (descriptors) que tornam possível a elegante e prática sintaxe de Models do Django.

Na aula "A caminho da metaclasse" evoluimos um exemplo gradualmente, em nove etapas, desde uma pequena classe com uma property até um proto-framework para definição declarativa de modelos com atributos validados, que ilustra o uso de uma metaclasse, um dos conceitos mais avançados em orientação a objetos.

Programação funcional e programação assíncrona

Em Python funções são objetos de primeira classe: podem ser atribuídas a variáveis, passadas como argumento e até criadas em tempo de execução. Isso possibilita o estilo funcional de programação, que tem ganhado importância ultimamente.

Depois de explorar um pouco desta teoria, partimos para a prática mostrando um dos principais usos de funções como objetos: a programação assíncrona, ou orientada a eventos. Neste tipo de programa usa-se intensivamente o padrão de callbacks, por isso a passagem de funções como argumentos e a definição de funções em tempo de execução viram práticas comuns.

Desenvolvemos um script cliente HTTP assíncrono usando o framework Tornado. Verificamos que ele é, em média, 5 vezes mais rápido que o script síncrono que realiza a mesma tarefa sem usar callbacks. Em seguida apontamos uma limitação da versão assíncrona, causada pela perda de contexto, um problema comum quando se trabalha com eventos e callbacks.

Então superamos este problema refazendo a solução assíncrona de três maneiras diferentes para comparar:
  1. definindo dinamicamente uma função, para carregar o contexto em uma closure; 
  2. definindo uma classe, e levando o contexto como atributos da instância;
  3. implementando uma co-rotina via função geradora; neste caso não precisamos nos preocupar com o contexto porque toda a lógica de uma requisição de dá no escopo local da função geradora, e o callback é engolido pelo o maquinário do Tornado.

Laboratórios

Conseguimos cobrir muitos conceitos em 12h. O feedback dos alunos foi muito positivo durante as aulas, mas sempre é possível melhorar, e nestas turmas a diferença entre uma aula na primeira turma e a mesma aula na segunda turma às vezes casos foi enorme, com melhorias importantes.

O desafio deste curso não é volume do conteúdo, mas a densidade: são vários conceitos sofisticados, que só com prática a gente pode dominar. Apresentei uma lista de exercícios durante o curso, e outra depois, para discussão no fórum de alunos, com meu apoio e supervisão. Nas próximas turmas as listas de exercícios se tornam laboratórios mais integrados ao fluxo do curso, estimulando a prática desde a primeira aula.

Se você já conhece Python mas gostaria de explorar alguns dos seus recursos mais avançados e exclusivos, experimente esta oficina. A pré-inscrição para a 3ª turma de Python para quem sabe Python já está no ar: basta fornecer seu e-mail.