27 de fevereiro de 2008

"Quem voa são os pássaros" -- Justiça


26/02/08, Parque dos Poderes, Campo Grande - MS.

Magia: Adicionando métodos à class por meio da instância

Um pouco de magia. Nada de mais.


>>> class Wakadoo(object): pass

>>> wakadoo = Wakadoo()
>>> # Lets create a function to be add to the 'wakadoo' object.
>>> def __setattr__(self, name, value):
self.__dict__[name] = value
print "Congrats. This method worked."


>>> # Look, the magic...
>>> setattr(wakadoo.__class__, __setattr__.func_name, __setattr__)
>>>
>>> wakadoo.var = "Ah-ha!"
Congrats. This method worked.
>>>
>>> print wakadoo.var
Ah-ha!
>>>

Storm: MAX e LIKE na mesma sentença



Qual a maneira storm de executar a seguinte query:

SELECT MAX(num) FROM operation WHERE num LIKE "8%"

Leve-se em consideração que a coluna 'num' é do tipo inteira (integer), logo o método "find" não aceitaria o parâmetro "%".

Solução 1 (mais stórmica):

store.find(Operation, Operation.num.like(SQL("'8%'"))).max(Operation.num)

Solução 2 -- Transcrito tal qual foi respondido pela storm-list (não testei):

store.execute(Select( Max(Account.id), Like(Account.id,'8%')) ).get_one()

Labirinto


Tradução Livre:
E LÁ TEMOS OS GUARDAS DO LABIRINTO.
UM SEMPRE MENTE, UM SEMPRE DIZ A VERDADE, E
UM SEMPRE BATE EM PESSOAS QUE FAZEM PERGUNTAS CAPICIOSAS

O Golfinho-livre agora capturado

Depois de dar vários sinais de que o golfinho estava desejando sair do mar aberto, finalmente cai nas redes de pescadores mercenários.

Dá para acreditar? É lamentável. Sun irá comprar MySQL. Foi-se o que era bom.

É certo que a Sun manterá o código aberto, mas não será a mesma coisa...

Vamos agora torcer para Postegre. Aliás, já estou até pensando em como vou migrar para ele.

Privado, Protegido? Python: uma "Open Kimono" Language

Quando questionado quanto à possibilidade de Python permitir "verdadeiros" atributos privados e protegidos, Rossum respondeu: """Não, Python continuará a ser uma "open kimono" language."""

"Open kimono"? O que ele quis dizer? Eis uma explicação:

The idea of the open kimono has become a financial cliche the last few years. (...)

To open the kimono means you’re being transparent, that you’re telling us the straight story, that these numbers can be trusted.


Tradução livre:

A idéia do open kimono se tornou um clichê financeiro nos recentes últimos anos. (...)

Abrir o kimono significa você estar sendo transparente, que você está nos dizendo a história franca, que esses números podem ser confiáveis.

Tutorial de Storm em nosso idioma


Finalmente minha primeira contribuição para a comunidade. Depois de uns dias de trabalho no google docs -- ah agora estou usando ele --, pesquisas em dicionários, google e tals finalizei a tradução (versão 'beta') do Tutorial de Storm (CLIQUE AQUI PARA VER).

Como o pessoal da comunidade já apontou, ele ainda carece de algumas correções terminológicas, além disso há alguns pequenos erros de masculino-feminino e plural.

Para quem não conhece, Storm é um promissor ORM lançado pela Canonical para funcionar concretamente no Launchpad e no Landscape.

Pythonista é assunto do Rails Podcast Brasil


A-ha! Tive meus minutos de fama (não tanto, mas foi legal). No último PODCAST (aos 35 minutos) da comunidade Ruby on Rails Brasil figurava entre os assuntos um artigo ("de um novo blogueiro nacional") intitulado Rails alavanca Python.

O artigo em questão foi objeto de um post do Júlio Monteiro (inclusive foi ele quem me avisou) que foi parar no Planeta Ubuntu e no Planeta Ruby on Rails (esse último eu não vi), o Akita então leu o meu artigo e [provavelmente] colocou-o na pauta do podcast.

À comunidade Rails minhas saudações :)

Enquanto isso na sala da justiça

[Acredite, essa conversa realmente aconteceu]

Larissa: "Luiz, você conhece o Carlos?"
Taís: "Você conhece a Noemi?"
Luiz: "Não, mas eu conheço o Wagner."
Larissa: "O Wagner? De Aquidauana*?"
Luiz: "Não, do SESC."


* Aquidauana é uma cidade pequena do interior.

Módulos ou Classes; Funções ou Métodos

"Tudo em classes", era quase sempre o que eu fazia, exceto em módulos de abstração; mas, se eu precisasse de uma única função que nem sequer recebia argumentos, eu a colocava numa classe. E por essa razão eu tinha que freqüentemente importar a classe de dentro do módulo, instanciá-la na classe em que estava usando, e eventualmente passá-la como argumento para outra classe e por aí afora.

Um certo dia eu resolvi dar uma olhada em Django, e qual minha surpresa, ele não coloca tudo em classes (A-ha!). Tanto que até a camada View (controller) consiste em funções. A partir de então percebi que o uso excessivo de classes pode atrapalhar em vez de ajudar, e reformulei as coisas. Por essa razão mudei minha regra de quando der ponha em classe para: primeiro pense em funções e se precisar transforme elas em métodos, e assim se fará uso mais adequado do suporte que Python propicia às funções: objetos de primeira classe.

Dessa forma, pensei em alguns pontos que podem indicar a desnecessidade do uso da classe. Veja-se:

# __init__ não faz nada ou o que ele faz pode ser feito fora.
É um bom indicativo de desnecessidade. É claro que é apenas um indicativo, não é regra, existem outras razões que justificariam a classe, mas pode ser que o __init__ não receba argumentos de modo que o que ele faz pode ser feito no escopo global do módulo.

# A classe não funciona como objeto.
Parece um contradição, mas não é. É sabido que em Python (quase) tudo é um objeto, mas isso quer dizer que tudo é tratado como objeto, mas não significa que tudo funciona como objeto; vezes há que os métodos da classe só te devolvem alguma coisa, mas você não faz alguma coisa com a classe, deveria ser mais um módulo que uma classe -- note que estou usando "módulo" como sinônimo de conjunto de funções, está certo que os módulos podem conter classes e funções ao mesmo tempo).

Ilustrando: imagine uma máquina de café em contrapeso com o próprio café: Na máquina a gente coloca pó de café, água, aperta um botão e ela devolve café. Essa máquina funciona como módulo: a gente alimenta com alguns argumentos e ela retorna café, ao passo que o próprio café é o objeto, porque ele pode ser manipulado como objeto: pode ser bebido, ser vendido, ser jogado fora etc. Além disso ele possui atributos como forte, fraco, doce, amargo.

# Nem sempre a própria instância precisa passar a si mesma como argumento para outra classe.
Considerando que você procura evitar singletons desnecessários, se uma instância está fornecendo "self" como argumento para algum __init__ (que não seja a super-classe), não significa que a primeira instância precisa ser uma classe, podemos usar um terceiro módulo que importará aquele conjunto de funções e passará como argumento para outro componente, assim deixamos as coisas mais simples.

É isso em IMHO.

Achar e mudar

Recentemente surgiu a necessidade de encontrar e alterar determinadas expressões dentro dos arquivos.py de todos os subdiretórios de uma pasta. Segue o código.

#!/usr/bin/env python

# changetool.py


import os, os.path

def run():
 print "At any moment type '@quit@' to quit."
 path = raw_input("Dir path ('enter' for local): ")
 if path.strip() == '@quit@':
     return
 find = raw_input("Find: ")
 if find.strip() == '@quit@':
     return
 replace_for = raw_input("Replace for: ")
 if replace_for.strip() == '@quit@':
     return
 if not path:
     path = "."
 tree = [item[0] for item in os.walk(path)]
 py_files = list_py_files(tree)
 replace(py_files, find, replace_for)
 print ""
 another = raw_input("Replacements done. "
                     "Do you want to do another one (y/n)? ")
 if another.lower().strip() == 'y':
     run()

def list_py_files(dirs):
 files = []
 for path in dirs:
     files += [os.path.join(path, i) for i in os.listdir(path)
               if i.endswith(".py") or i.endswith(".pyw")]
               #or i.endswith(".glade") or i.endswith(".st")]
 return files

def replace(files, find, replace_for):
 print ""
 print "---------------------------------"
 for file in files:
     lines = open(file).readlines()
     new_lines = []
     for index, line in enumerate(lines):
         if find in line:
             print "File:", file
             print "Line number:", (index+1)
             print "Found:", line.strip()
             line = line.replace(find, replace_for)
             print "Replaced for:", line.strip()
             print "---------------------------------"
         new_lines.append(line)
     if lines != new_lines:
         open(file, "w").write("".join(new_lines))

run()


>>> """ Se você tem alguma contribuição, melhoramento ou sugestão para fazer, fique à vontade. """

Rails alavanca Python

Como o pessoal do meio já deve estar sabendo, Python foi a linguagem que mais cresceu em 2007 em popularidade segundo o Tiobe Index (noticiado em português pelo blog do Caio Moritz).

Pois bem, a minha teoria é: A bolha de Rails estourou soprando na embarcação de Python.

É que nesse mundo doutrinado por Java e .Net as pessoas costumam usar o que todo mundo usa, e às vezes deixam de experimentar coisas melhores.

Mas de repente, não mais que de repente, em 2004, provavelmente em razão do Zope, despontou Python -- uma linguagem nova com idéias arrojadas, mas ainda não era comercial o suficiente para causar grandes mudanças.

Mas de repente, não mais que de repente, em 2005 surgiu "Ruby on Rails" cujo o nome já diz a linguagem na qual foi escrito: Ruby. Pela facilidade que o framework proporcionava e um conjunto de circunstâncias favoráveis Rails se tornou rapidamente hype. E 2006 foi o ano de Ruby. Tanto que Rails aparecia em revistas e era constantemente citado nos fóruns de tecnologia por aí afora.

Então vêm os winds of change. Quem nunca tinha se interessado, ficou conhecendo a fama de Rails e dessa maneira descobriu-se que existia um tal Ruby (que quase ninguém conhecia), e um número significativo de programadores, experimentando esse açúcar, migrou para Rails e por conseqüência adotaram Ruby.

Aqui entra o efeito borboleta. Ruby é indissociável de Python, ambas têm muitas vantagens, como a ausência do perlishismo de Perl (Ruby ainda conserva um pouco disso mas isso deve mudar), da bagunça de PHP e da verbose ilegível de Java. E como a febre Rails passou causando mudanças no mundo, as novas tecnologias continuaram a chamar a atenção, e assim, nesse último ano, muitos analisando friamente as duas tecnologias optaram por Python.

Talvez não tenha sido o fator preponderante para impulsionar os números, há que se levar em consideração outros como o próprio crescimento contínuo de Python (que já vinha acontecendo) , além do crescimento do uso de Linux (com foco em Ubuntu) que faz ampla utilização de Python, mas que Rails pareceu ajudar, isso foi.

De uma maneira ou de outra, Ruby e Python vão seguir adiante atraindo olhares atentos e desatentos, e mais uma vez a canção será entoada: listen to the wind of change...