Deixando o interpretador Python maluco por diversão e lucro, ou Como se livrar de um colega de trabalho desenvolvedor Python

Você está lá, em apenas mais um dia comum de trabalho (ou diversão), debugando um sistema complexo e tentando entender porque diabos algo que deveria acontecer não acontece. Você consegue reduzir o seu problema a uma linha de código, que não se comporta como você espera:

>>> print 42 == 0
True

O resultado foi verdadeiro, ou seja, 42 realmente é igual a 0 no momento em que esta comparação roda! Mas como assim?! Em Python não é possível reabrir a classe dos números (int), reescrever os métodos de comparação para fazer isso dar certo.
Lembre-se que esta comparação estranha está no meio de um sistema complexo. Assim:

algo_que_deixa_interpretador_maluco()
print 42 == 0

Explicação: A função algo_que_deixa_interpretador_maluco está modificando o objeto “número inteiro 42” (mesmo os números são objetos). Mas os números são objetos imutáveis, como assim você modificou o valor de 42? Um número inteiro em Python (na verdade, CPython) é representado por uma struct do C, que entre outras coisas, contém um long do C com o mesmo valor  – o atributo ob_ival.

Simplificando uma longa história, quando temos uma comparação de números, ela é repassada para o nível do C, e os atributos ob_ival da struct C são comparados com o operador == do C. Basta então mudarmos o ob_ival do objeto “número 42” que podemos influenciar na comparação.

E para mudar o valor de ob_ival? Como é possível acessar e modificar o estado interno e a memória do interpretador? Com o módulo ctypes, da biblioteca padrão, podemos acessar do Python os tipos do C. Basta então conseguirmos achar na memória a struct do número 42. Mas isso é fácil, a função builtin id retorna exatamente o lugar na memória onde o objeto está. Com isso, temos tudo que precisamos.

import ctypes

if hasattr(ctypes.pythonapi, 'Py_InitModule4'):
    Py_ssize_t = ctypes.c_int
elif hasattr(ctypes.pythonapi, 'Py_InitModule4_64'):
    Py_ssize_t = ctypes.c_int64
else:
    raise TypeError("Cannot determine type of Py_ssize_t")

class PyObject(ctypes.Structure):
    pass # incomplete type

class PyObject(ctypes.Structure):
    _fields_ = [('ob_refcnt', Py_ssize_t),
                ('ob_type', ctypes.POINTER(PyObject))]

class PyIntObject(PyObject):
    _fields_ = [('ob_ival', ctypes.c_long)]

forty_two_object = PyIntObject.from_address(id(42))
forty_two_object.ob_ival = 0

print 42 == 0

Neste código, estamos primeiro conseguindo o endereço do objeto 42 (linha 20), depois criando a struct do ctypes (ponte entre o Python e a struct C), depois alteramos o ob_ival do 42 para 0, na memória do interpretador (linha 21).

A partir daí, quando o Python fizer a comparação entre o número 42 e 0 (linha 23), ela será verdadeira, já que seus ob_ival são iguais.

Extensões em C ou mesmo código Python com ctypes mal testados podem causar consequências imprevisíveis e bugs dificílimos de reproduzir, mesmo onde parece impossível. Mas também tem usos interessantes: Pense em um dos inúmeros jogos que suportam Python como Civilization IV, Battlefield 2 e Piratas do Caribe Online. É possível fazer um script usando o mesmo princípio que modifica, por exemplo, as variáveis de controle de vidas do jogador, posição etc.

Publicidade
Publicado em C, hack, Python. Tags: , , . 11 Comments »

Corrida de vetores, agora mais nerd

Quando eu estava no colegial, adorava jogar com meus colegas um joguinho meio matemático, entre nós conhecido como Corrida de Vetor.  É um jogo bastante popular, simples e divertido, bom para o tempo passar mais rápido naquelas aulas de chatas de Geografia. Tem uma versão online aqui.

Esses dias apareceu no meu Google Reader (share do ricbit) um post explicando um algoritmo para encontrar o caminho mínimo, dada a pista. Resumindo o post, o algoritmo é bem simples, usa apenas um grafo com todos os estados possíveis e uma busca em largura.

Cada vértice do grafo representará a posição na pista em x em y, e a velocidade em x e em y. Pra montar o grafo com todos os estados, é assim:

  • Começar o grafo com um vértice, que é a posição de largada com velocidade zero e colocá-lo na fila de vértices a processar.
  • Enquanto ainda tiver vértices na fila a processar:
    • Processar o próximo vértice na fila de vértices a processar. Colocar os novos vértices resultantes no fim da fila.

OK, mas o que significa este “processar o vértice” ? Significa gerar todos os vértices alcançaveis a partir do atual, ou seja, os vértices que são atingidos partindo do vértice atual com a velocidade que ele tem e todas as possíveis variações na velocidade (combinação de +1, 0 ou -1 na horizontal com +1, 0 ou -1 na vertical).

Tendo o grafo com todos os possíveis estados do jogo, o caminho mais curto tem que estar no grafo. Como todas as arestas tem o mesmo peso, nem precisamos usar o algoritmo de Dijkstra para achar o caminho mais curto. Ele será o primeiro a ser encontrado usando uma busca em largura. Na verdade, nem precisamos gerar todos os estados, podemos parar ao achar o fim da corrida, que é como eu implementei.

Como eu gostava muito do joguinho, fiz um programinha que lê uma pista em um arquivo texto, calcula o caminho mais curto e gera um gráfico com o caminho e uma representação das velocidades. O gráfico (tosquinho, eu sei), é assim:

Resultado do programa

Os quadrados vermelhos representam os pontos onde o jogador decide o que fazer e o tom de vermelho representa a velocidade, quanto mais escuro mais rápido.

Podemos ver que até o algoritmo “rouba” no jogo, passando pela grama pra evitar algumas curvas muito fechadas. Acho que isso até era permitido na regra sim.

Código-fonte e arquivo de pista

Dependências: PIL, python-graph

Publicado em Misc, Python. Tags: . 1 Comment »

Yahoo! Open Hack Day Brazil 2008

Neste fim de semana eu participei do Yahoo! Open Hack Day Brazil. O evento foi feito pelo Yahoo! no Senac de Santo Amaro e as pessoas se divertiram com as APIs abertas do Yahoo!, fazendo mashups e algumas outras maluquices. Durou das 08:00 de sábado até as 20:00 de domingo, 36 horas ininterruptas de hacking.

Só tenho coisas boas a dizer sobre o evento. O ambiente era muito confortável, a comida estava muito boa e fomos atendidos 100% do tempo, os hacks estavam muito legais, eles nos pegaram e levaram até estações de metrô e trem. Enfim, a organização do Yahoo! está de parabéns.

Eu como todo bom engenheiro eletricista fui ao HackDay munido de uma protoboard, muito fio, vários LEDs e mais alguns componentes, ainda sem uma idéia mas com a certeza que seria útil.

O pessoal do GruPy-SP devidamente uniformizado formou um time e aos poucos várias pessoas foram se juntando ao time. Éramos um time enorme, com 11 pessoas. Tivemos várias idéias, como pode ser visto no brainstorm abaixo:

Brainstorm do projeto

Brainstorm do projeto

O projeto era um eventômetro: um medidor de quanto burburinho um evento está gerando no Twitter e Flicker. Várias idéias foram dadas no brainstorm: um algoritmo de clustering para posts no Twitter e Flickr, usar o Quartz Composer e o Cocos2D para gerar uns efeitos legais, Yahoo! Blueprint para fazer uma aplicação para celular, eletrônica para sair do comum e mais um monte de outras coisas.

Eu fiquei com o hardware do nosso hack, junto com o Luiz Vitor Martinez Cardoso. Depois que terminamos o hardware eu fui para o script que baixava as informações do Twitter e Flickr.

Eu mostrando a protoboard

Eu mostrando a protoboard

Hardware do projeto

Hardware do projeto

A maluquice acima é um Arduino controlando os LEDs e o buzzer na protoboard. Os LEDs formam a palavra Yahoo! e piscam com uma frequência determinada pela quantidade de posts sobre o evento no Flickr na última hora. A quantidade de letras acesas do Yahoo! depende da quantidade de posts sobre o evento no Twitter na última hora. O buzzer tocava uma musiquinha cuja velocidade era a mesma com que os leds piscavam. Tudo era controlado pelo Arduino, uma plataforma aberta de hardware muito fácil de começar a fuçar, que recebia os dados do computador pela USB.

Usar os LEDs chamou muita atenção no evento, o tempo todo tinhamos jornalistas e outros participantes curiosos em saber o que era aquilo tão diferente.

Também tinhamos uma aplicação feita com Cocos2D que mostrava os últimos posts no Twitter e Flickr.

No final, não ganhamos os prêmios originalmente propostos, mas ganhamos outro prêmio. E a razão é bem simples: nosso projeto era bastante inútil, usava só uma API do Yahoo! (a do Flickr) e tinha um time muito maior que os outros. Mas ele era muito legal e diferente, então eles criaram mais 4 categorias e aí sim ganhamos um prêmio. A categoria foi chamada “What the hack was that?”, que reflete bem a surpresa com o nosso hack.

Concluindo, foi um fim de semana muito divertido, fiquei feliz com o nosso hack, com as pessoas que conheci, com os hacks legais apresentados e claro, com o prêmio.

Lameiro feliz com o prêmio

Lameiro feliz com o prêmio

“import antigravity” vai funcionar no Python 3

O Python 3 ganhou um novo easter egg: import antigravity

O novo easter egg (commitado semana passada) é uma referência a uma tirinha do famoso XKCD, em que o personagem consegue voar apenas digitando “import antigravity”, se remetendo à facilidade de uso da linguagem. O novo módulo quando importado fará com que um browser seja aberto e a tirinha carregada da web.

O easter egg se junta aos já famosos from __future__ import braces e import this.

Publicado em Python. Tags: , . 1 Comment »

Gerando apresentações beamer for dummies

O beamer gera apresentações muito legais, não há como duvidar. Se você ainda não o conhece, gaste um pouquinho do seu tempo e você fará apresentações muito mais bonitas e estruturadas do que as que você está acostumado a fazer no PowerPoint, OpenOffice ou Keynote.

Mas ele tem um problema: o LaTeX. Eu até gosto do LaTeX e concordo que ele gera documentos com formatação bonita e consistente, já escrevi alguns documentos grandes com ele, mas pra fazer qualquer coisa eu preciso lembrar um markup muito chato e comandos mal-documentados.

Hoje eu descobri uma ferramentinha que resolve boa parte do problema: yml2tex. É um programa muito simples que converte um arquivo texto em notação YAML para um arquivo TeX, quase pronto para ser “compilado” pelo pdflatex (o quase é porque a versão atual deixa o nome do autor hardcoded no “template” então você vai precisar editar).

Claro que com um YAML não dá pra aproveitar nem metade do poder do beamer, mas já fica bom. Ele faz 3 coisas e só isso: Gera o índice da apresentação, slides com “bullets” seguindo a hierarquia do YAML, inclui fotos e código-fonte (lindamente colorizado pelo pygments). Isso é suficiente para muitos casos. Para quem precisar personalizar mais alguma coisa, pode abrir o arquivo TeX e mandar bala.

Você pode ver um exemplo de apresentação gerada de um arquivo YAML. O blog do autor tem mais detalhes de uso.

Exemplo de slide gerado pelo yml2tex

Exemplo de slide gerado pelo yml2tex

Publicado em Python. Tags: , , . 1 Comment »

Os podcasts que eu ouço

Quando o Bruce Eckel veio pro Brasil para a PyConBrasil 2008 e para o workshop de design patterns, ele perguntou quem escutava podcasts regularmente e bem menos gente do que eu esperava levantou a mão. Então ele recomendou alguns podcasts e enfatizou que ouvir podcasts era quase como ir a conferências, mas ainda mais prático você ouve quando puder. O Humberto Diógenes então fez um post legal indicando os podcasts que ele ouve e eu decidi fazer o mesmo. Os podcasts abaixo não estão em ordem de preferência:

This Week in Tech – Muito bom. Conta com a presença regular do polêmico John C. Dvorak. Normalmente são longos (mais de 1 hora). As edições que eu mais gostei foram sobre o The Internet Archive, o lançamento do Microsoft Live Mesh e sobre como a internet, blogs e twitter estão influenciando o jornalismo. Periodicidade: Semanal.

Capa TWiT

This Week in Tech

FLOSS Weekly – Mais um podcast com o Leo Laporte. Neste podcast ele e Randal Schwartz (sim, o cara do Perl e agora Smalltalk) entrevistam personalidades do software livre, normalmente core developers de projetos grandes como o Drupal, Python, Audacity, mas também pessoas não tão ligadas a projetos como o Maddog, Larry Augustin e Ward Cunningham. Os episódios que eu recomendo são: Ward Cunningham (muito bom!), Larry Augustin, Maddog, Jeremy Allison. Periodicidade: Deveria ser semanal, mas de vez em quando demora mais, de vez em quando menos. Nos últimos meses eles tem conseguido manter a regularidade.

FLOSS Weekly

FLOSS Weekly

Software Engineering Radio – Podcast já tradicional (mais de 3 anos e 100 episódios) que sempre conta com entrevistas interessantes normalmente com acadêmicos de várias áreas ligadas a software, por exemplo, linguagens funcionais, arquitetura de software, métodos ágeis, SOA, sistemas embarcados, sistemas distribuídos etc. Meus episódios preferidos: Static Code Analysis, Garbage Collection and Transactional Memory, Anders Hejlsberg (o cara do C#, Delphi e Turbo Pascal), LISP, Small Memory Software. Periodicidade: De dez em dez dias.

Software Engineering Radio

Software Engineering Radio

This Week in Django – Este podcast comenta os últimos desenvolvimento do Django no SVN, aplicações interessantes feitas com o Django e entrevista pessoas ligadas a comunidade do framework. Periodicidade: Semanal.

This Week in Django

This Week in Django

Publicado em Python, Web. Tags: , , . 5 Comments »

Saiu o Python 2.6!

Hoje saiu a primeira versão estável do Python 2.6. O principal objetivo deste release é começar a trilhar o caminho para o Python 3.0, que corrigirá problemas de design das versões anteriores.

Algumas destas correções tornam o código escrito para versões anteriores incompatíveis com o novo Python 3.0. A versão 2.6 é uma versão intermediária que contém tanto funcionalidades das versões anteriores do Python quanto novidades do Python 3.0. Com esta versão intermediária os desenvolvedores podem começar a verificar a compatibilidade de suas aplicações com a futura versão 3.0 do Python e já começar as adaptações, garantindo uma transição suave entre as versões.

A versão 2.6 é compatível com as versões anteriores, mas auxiliará na migração emitindo avisos caso haja construções incompatíveis com a versão 3.0. Além desta versão intermediária, a ferramenta 2to3 é capaz de realizar automaticamente muitas conversões (mas não todas).

As novidades da 3.0 já incorporadas na 2.6 são muitas: novos módulos para processamento paralelo e codificação/decodificação JSON, tratamento de frações, correção de mais de 600 bugs, otimizaçõesum diretório de pacotes por usuário (o que facilitará a instalação em ambientes compartilhados), o novo método str.format em substituição ao operador % das strings, decorators para classes, melhorias na documentação (que ficou muito mais bonita usando o Sphinx). Enfim, são muitas novidades interessantes e eu não falei nem da metade!

Agora você pode fazer o download, ler o changelog e ver a apresentação do Guido. Boas migrações!

Publicado em Python. 1 Comment »

PyConBrasil 2008

Para os que perderam a PyConBrasil 2008, segue o link da minha lightning talk sobre extensões para o Elixir/SQLAlchemy. Várias outras palestras legais estão no SlideShare com a tag pyconbrasil2008. Confiram!

Destaque especial para a palestra do Daniel Baggio, sobre reconhecimento de imagens com demonstrações ao vivo, na minha opinião a melhor do evento.

Uma crítica construtiva às traduções do Ubuntu

A notícia quente da semana foi o lançamento do novo Ubuntu versão 8.04, que eu fiz questão de instalar.

Tudo funcionando bem: reconhecimento de hardware, particionamento, redimensionamento de NTFS e tudo mais. Era de se esperar, funcionava na versão anterior, não havia motivo para deixar de funcionar agora.

Mas com as traduções por alguma razão é diferente. O painel superior do GNOME conta com novos erros de tradução onde estava tudo certo nas versões anteriores. Alguns pequenos erros de tradução passarem é tolerável mas errar no painel principal do GNOME?! É simplesmente o principal programa do Ubuntu!

Em Aplicações->Acessórios temos o item “Consola” (provavelmente vindo do pt-PT), que antes era corretamente chamado “Terminal”.

Em Sistema->Preferências temos o item “Rato” (certamente vindo do pt-PT). A palavra mais usada no pt-BR para “Mouse” é “Mouse” mesmo.

Em Sistema->Administração temos o item “Testando hardware”, provavelmente vindo do inglês “Hardware testing”, que deveria ser traduzido como “Teste de hardware” ou “Testar hardware”.

E porque eu não vou lá e traduzo no Rosetta ao invés de reclamar? O Rosetta não conta com uma ferramenta de busca, que é requisitada desde 2005. Eu não vou achar essas strings na mão no meio de mais de outras 600 para o painel do GNOME.

Fiquei bastante feliz com a notícia que o brasileiro André Gondim é destaque nas traduções do Ubuntu, mas fica a crítica construtiva ao atual sistema de tradução: Não existe um processo de revisão da tradução, principalmente para os programas mais usados? Como é que uma tradução adequada foi perdida?

Slashdot e o sensacionalismo

Estou cansado do sensacionalismo da Slashdot.

A última foi com relação ao Python 3.0, reproduzido na íntegra abaixo:

“Organizations using Python will be affected in a major way by changes in store for the language over the course of the next twelve months, Linux.conf.au attendees were told this morning. The Python development community is working towards a new, backwards-incompatible version of the language, version 3.0, which is slated for release in early 2009. Anthony Baxter, the release manager for Python and a senior software engineer at Google Australia, said “We are going to break pretty much all the code. Pretty much every program will need changes.” Baxter also added another tidbit for attendees, saying that Python accounts for around 15 percent of Google’s code base.”

A notícia não é falsa (apesar de ser bem velha), o Python 3.0 vai realmente quebrar muito código. Mas ela não diz que praticamente todas as mudanças necessárias podem ser feitas por um script. Também não diz que o Python 2.6 vai continuar a ser desenvolvido e mantido por mais alguns anos, nem que talvez exista um 2.7. Também não diz que o Python 2.6 além de rodar código atual, avisará de quebras de compatibilidade com a versão 3.0. Se não bastasse todo o esforço feito, a instalação paralela de Python 2.6 e 3.0 será possível, o que garante que as aplicações continuarão rodando.

Fora que isso é pratica completamente normal. Perl 6, VB.NET, C# 2.0, PHP5, não faltam exemplos de linguagens que quebraram compatibilidade com seus antecessores em algum momento.

Porque tanto exagero? Será que é porque traz visitantes e receita com as propagandas? Ou será apenas incompetência editorial?

Publicado em Python. Tags: , . 1 Comment »