Zen do Python na prática

– Como é o jeito padrão de implementar árvore em python?

– Rapaz, até onde eu sei cada um implementa do jeito que precisa.

–  Sim, mas não tem um jeito “padrão”?

– Hum, acho que não.

– Então eu vou ter que implementar essa árvore e disponibilizar p/ cara p/ ele herdar dela e…

– Porque você precisa de uma árvore?

– Ah, eu tenho plugins e eles precisam retornar os menus e submenus na forma de uma árvore.

– Por que não diz ao cara apenas que ele precisa ter um atributo ‘children’ com uma lista dos filhos que por sua vez podem ter também o atributo children e assim até chegar na folha da ‘árvore’. Dessa forma ele fica livre para implementar do jeito que quiser.

– É, boa idéia…

É mais fácil pedir desculpa que pedir permissão

Anúncios

“Com mais dinheiro resolveremos nossos problemas!”

Trecho de um artigo no blog Productivity501 sobre um projeto de aumento nas taxas no estado de Michigan:

The thought of “if we only had more money we could fix our problems” is prevalent in government, business and personal life.  If your focus is on getting more money you will often overlook solutions that actually solve the problem.  Worse still, the “money” solutions often turn out to create new problems that are worse that what you were originally trying to fix.

Em livre tradução:

A idéia de que “se nós tivéssemos mais dinheiro nós poderíamos consertar nossos problemas” é predominante no governo, negócios, e vida pessoal. Se seu foco é em conseguir mais dinheiro você geralmente vai ignorar soluções que na prática resolvem o problema. Pior ainda, as soluções de “dinheiro” normalmente acabam criando novos problemas que são piores que os problemas originais.

Não poderia concordar mais.

Raycife: Agora com sombras

Apesar de ter aumentado consideravelmente a granularidade (tá parecendo coisa de z-buffer ou algo do tipo), corrigi um bug besta pelo qual as sombras não estavam aparecendo: O raio de luz estava com a direção invertida (luz – ponto_de_verificação, e não ponto_de_verificação – luz)…

Abaixo, o resultado: 100×100 pixels e 100 raios/pixel (26 minutos, mas usando o computador enquanto processava):

Próximos passos: resolver essa bronca de granularidade e adicionar reflexão especular.

Status do projeto: raycife+

First full window of raycife

Esse é o estado atual, apenas com iluminação ambiente e a componente difusa (e um belo bug de ordenação). A imagem de referência pode ser encontrada no fim dessa página.

Dados: Janela 200×200 com 20 raios por pixel.

Tempo de processamento num Celeron 440 com 1 GB de RAM: +-15 minutos (muito lento…)

Profiling python com cprofile

Durante o desenvolvimento do raycife+, a performance estava ficando impraticável, chegando a cerca de 3 a 4 minutos para uma cena simples de 100×100 pixels e 7 objetos no meu velho celeron. Seguindo as dicas desse site, rodei o cprofile e pude ver onde poderia ganhar tempo.

No arquivo principal do programa esse código que executa a função main com os argumentos fornecidos na string e salva o resultado num arquivo de log.

if __name__ == '__main__':
    import cProfile
    cProfile.run('main(["raycifeplus.py", "./samples/cornellroomsmall.sdl"])' filename='raycife.cprof')

Para ler o resultado do arquivo de saída:

from pstats import Stats
stats = Stats("raycife.cprof")
stats.sort_stats('time').print_stats()

Exemplo da saída:

Mon Apr 21 11:23:35 2008    raycife.cprof

37298787 function calls in 237.746 CPU seconds

Ordered by: internal time

ncalls  tottime  percall  cumtime  percall filename:lineno(function)
1  168.955  168.955  237.734  237.734 ./raycifeplus.py:71(render)
26660558   46.400    0.000   46.409    0.000 /home/lauro/dev/raytracer/raycifeplus/gameobjects/vector3.py:165(__iter__)
5723042    9.791    0.000    9.807    0.000 /home/lauro/dev/raytracer/raycifeplus/gameobjects/vector3.py:265(__sub__)
2422914    4.633    0.000    4.636    0.000 /home/lauro/dev/raytracer/raycifeplus/gameobjects/vector3.py:369(__rmul__)
2422914    4.114    0.000    4.125    0.000 /home/lauro/dev/raytracer/raycifeplus/gameobjects/vector3.py:224(__add__)
10000    2.927    0.000    4.841    0.000 ./raycifeplus.py:80(render_pixel)
1472    0.478    0.000    0.916    0.001 ./raycifeplus.py:99(trace_point)
841    0.129    0.000    0.299    0.000 /home/lauro/dev/raytracer/raycifeplus/objfile.py:30(intersect)
1    0.119    0.119    0.182    0.182 /home/lauro/dev/raytracer/raycifeplus/pnm.py:18(write)
10000    0.044    0.000    0.044    0.000 /home/lauro/dev/raytracer/raycifeplus/pnm.py:15(set_pixel)

Nesse caso, deu para ver que parte do tempo era perdido no módulo vector3, uma implementação de vetores em 3 dimensões usando python.

No próximo vou falar sobre uma tentativa rápida de implementar a mesma funcionalidade usando C++ e criando o binding usando o SIP.

Nota: O código acima ainda poderia ser refinado para receber argumentos na linha de comando mas como é apenas um teste rápido, pode ficar p/ depois uma flag “-p” para habilitar o profiling.

Nota2: Sim, eu sei que a otimização prematura é a raíz de todo mal mas nesse caso é um teste pontual que não vai mudar o algoritmo, além de poder conhecer novas tecnologias 🙂

A distribuição Linux perfeita!

Linux evolution comic

Traduzindo:

– Eu tenho 32 configurações do Linux rodando virtualizadas. E também tenho um algoritmo genético realizando seleção e mutação para produzir…

– A distribuição Linux definitiva!!!

– <pinguim de boné> Já existe, se chama Ubuntu.

– Eu não acredito em criacionismo…

Fonte: zoitz

‘Use’ o Google no seu site (com Python!)

Pelo menos é o que dá a entender o conceito do AppEngine.

Você desenvolve usando Python (Vem com django instalado, apesar de algumas mudanças \o/ ), manda o código e lá é hospedado e servido pela infra estrutura do Google. O pacote gratuito dá direito a 500MB de espaço e cpu/tráfego para +- 5 milhões de page views. Há suporte para acesso aos serviços de dados (Datastore/BigTable) e contas (Google Accounts).

Virtualizando as janelas

O Centro de Informática da UFPE faz parte do MSDN Academic Alliance e como resultado temos acesso a alguns softwares da MS. Semana passada baixei a imagem do Windows XP e estava (ainda estou) com preguiça de fazer backup -> instalar windows -> instalar ubuntu -> instalar programas, portanto parti p/ virtualização.

Como primeira opção, já que estava instalado, tentei o QEMU. Muito lento, mesmo com o kqemu instalado. Começava a copiar uns arquivos e parava. Quando estava com o controle do mouse e teclado (grab), o computador ficava completamente sem responder (Tinha que matar o processo via ssh).

Então a solução seguinte foi o VMWare Player, apesar da bronca de criar uma nova imagem p/ ele. No QEMU basta uma imagem simples de HD ou CD mas o VMWare tem um formato próprio com uns arquivos extras.

Para isso, usei um script de Marcelo ‘setanta’ Lira, que ele usa no INdT p/ criar o Maemo SDK VMWare Appliance. Bastou modificar algumas variáveis dentro dele, como a imagem a ser usada (ele usa a do Xubuntu) e o caminho padrão com os dados.

Resultado: Nesse exato momento, rodando o XP redondo, mas claro que não como um desktop decidado mas para o que preciso é suficiente. Ah, e com suporte a parar/reiniciar a qualquer momento 😀

Manipulando imagens com PIL – básico

Bem, com uma lista já enviada agora tenho um pouco mais de tempo, embora ainda faltem mais duas: uma (escrita, já atrasada) e outra dentro de 2 semanas. 🙂

Segue abaixo uma visão básica do que precisei usar da PIL nesses trabalhos (basicamente abrir, pegar pixels, colocar pixels, salvar)

Abrindo uma imagem

img = Image.open(filename)

Nesse trabalho eu tive que usar apenas imagens monocromáticas no modo ‘L’ ao invés de RGB (ou seja, 1 valor por pixel ao invés de 3), e para ‘forçar’ isso, o comando poderia ter sido o seguinte:

img = Image.open(filename).convert(‘L’)

Pegando os dados

Como eu estava usando imagens pequenas, de 512×512, o método que usei foi o ‘getdata()’ no objeto imagem criado anteriormente que retorna um objeto com suporte a iteração com os dados dos pixels.

Escrevendo os dados

Para escrever, basta usar o ‘putdata’ que escreve no objeto a partir da posição 0 (ele enxerga a imagem como um vetor unidimensional no caso do [get|put]data, sendo linha após linha sequencialmente). Opcionalmente argumentos scale; que multiplica todos os pixels; e offset; a partir de onde começa a copiar; podem ser usados.

pixel = value*scale + offset

Salvando

Assumindo que você tem um objeto imagem e que salvá-lo, ele possui um método save (D’oh!) que recebe como argumento o nome do arquivo de saída.

img.save(‘foobar.png’)

Conclusão

Bem, esse foi praticamente um ‘hello, world!’ do PIL, mostrando que pelo menos para essa manipulação básica de imagens é uma biblioteca bem simples e direta de usar. Para mais informações: API do módulo Image.

Nos próximos posts, numpy, filtros, etc…