quinta-feira, 29 de janeiro de 2009

Propriedades e acessores

Em Java e em C++ há um bom motivo para que os atributos sejam sempre privados: preservar a interface das classes.

Por exemplo, imagine que temos uma classe que representa o registro de uma pessoa. Nela temos a idade. Sendo um número inteiro, poderia ser um atributo público:
Person person;
person.age = 23;
std::cout << person.age << std::endl;


Faz sentido. Agora imagine que mais tarde descobrimos que é preciso fazer um tratamento do valor recebido – para estar numa faixa aceitável, por exemplo…

Sem alterar a interface – e efetuar uma refatoração total de todo código onde ocorre instância – é impossível.

Então, em Java e C++ é importante usar métodos acessores e manter os atributos privados. Dessa forma qualquer alteração futura pode ser feita na classe sem alterar o restante do código:
Person person;
person.setAge(23);
std::cout << person.getAge() << std::endl;

Propriedades

Já em Python isso não faz sentido!

Em Python, além de atributos e métodos, há as propriedades. Então atributos podem ser públicos e, caso seja necessário adicionar alguma lógica na leitura ou gravação do atributo, basta substituí-lo por uma propriedade, sem prejudicar a interface.
class Person(object):

    def __init__(self):
        self.name = ""
        self.age = 0


Substituindo por propriedades:
class Person(object):

    def __init__(self):
        self.name = ""
        self.__age = 0

    def _get_age(self):
        return self.__age

    def _set_age(self, age):
        if 0 <= age < 150:
            self.__age = age

    age = property(_get_age, _set_age)


E a interface permanece imutável!

Aviso: não use propriedade quando não for necessário! Use atributo público. Um pouco de desempenho não faz mal a ninguém, mesmo em scripts.
Aviso²: testei esse código no prompt e não funciona, mas funciona em script. Se alguém puder descobrir o que está acontecendo, agradeço.

[update 2009-08-26]Usando IPython funcionou corretamente, portanto não sei o que causou o erro. =P

Assim assim, valeu Thiago Coutinho por tê-lo identificado (acho que ainda ocorre durante a interpretação em linha do CPython tradicional).[/update]

Usando metaclasse

Uma forma de implementar automaticamente autopropriedades foi sugerida por Guido van Rossum em Unificando Tipos e Classes (original).

Usaremos uma metaclasse:
class autoprop(type):

    def __init__(cls, name, base, dict):
        super(autoprop, cls).__init__(name, base, dict)
        props = {}
        for method in dict:
            if method.startswith("_get_") \
                or method.startswith("_set_") \
                or method.startswith("_del_"):
                props[method[5:]] = True
        for prop in props:
            fget = getattr(cls, "_get_" + prop, None)
            fset = getattr(cls, "_set_" + prop, None)
            fdel = getattr(cls, "_del_" + prop, None)
            setattr(cls, prop, property(fget, fset, fdel))

A ideia por trás dessa metaclasse é identificar métodos iniciados por _get_, _set_ ou _del_ e criar propriedades a partir daí. O método iniciado por _get_ representa a leitura, _set_ representa a escrita e _del_ representa a remoção.

Nossa classe então ficaria assim:
class Person(object):
    __metaclass__ = autoprop

    def __init__(self):
        self.name = ""
        self.__age = 0

    def _get_age(self):
        return self.__age

    def _set_age(self, age):
        if 0 <= age < 150:
            self.__age = age

Usando decoradores

Mas realmente, ao contrário da metaclasse para singleton, usar metaclasse para autopropriedade é como usar uma escopeta para espantar uma mosca.

Vamos usar decoradores!

O decorador @property pode ser usado para criar propriedades. Funciona muito bem e deixa o código bastante limpo:
class Person(object):

    def __init__(self):
        self.name = ""
        self.__age = 0

    @property
    def age(self):
        return self.__age

    @age.setter
    def age(self, age):
        if 0 <= age < 150:
            self.__age = age

A função deve ter o nome da propriedade. O método de escrita deve chamar-se fset, o de leitura fget e o de remoção fdel. A parte mais feia desse código é o retorno. =)

**

Fica aqui a dica!

[]'s
Cacilhas, La Batalema

quarta-feira, 28 de janeiro de 2009

Interface fluente

Outro pattern interessante é conhecido como carrying return (não confundir com carriage return, carácter com código ASCII 13).
[update 2009-01-29]Esse era o nome dado há uns anos atrás, quando conheci esse pattern. Porém ele não ganhou espaço entre os programadores na época e poucos continuaram usando (como eu). =P

Hoje em dia ele voltou com o nome Fluent Interface, Interface Fluente.

A propósito, troquei o título deste artigo para usar uma linguagem mais nova e mais fácil de ser reconhecida.

Valeu Walter e Lucas![/update]


Há outros nomes, mas não consigo encontrar no São Google, pois não é um pattern muito usado.

Parecido com Smalltalk


Imagine que você tem uma classe Java que recebe muitos parâmetros na instanciação:
Person person = new Person(
aString, aDate, anotherString, aLoad, aPerson, anotherPerson
);


A quantidade de argumentos pode explodir ao extremo. Python pode apresentar maior visibilidade quanto ao significado dos parâmetros:
person = Person(
name=aString,
birthdate=aDate,
id=anotherString,
load=aLoad,
father=aPerson,
mother=anotherPerson
)


Smalltalk, uma linguagem bem mais antiga do que Python ou Java, já tinha uma abordagem bem mais elegante:
person := Person new.
person
setName: aString;
setBirthdate: aDate;
setId: anotherString;
setLoad: aLoad;
setFather: aPerson;
setMother: anotherPerson.


É possível conseguir um código similar em Java usando acessores tipo setter:
Person person = new Person();
person.setName(aString);
person.setBirthdate(aDate);
person.setId(anotherString);
person.setLoad(aLoad);
person.setFather(aPerson);
person.setMother(anotherPerson);


Finalmente


Mas é possível obter um código ainda mais elegante usando o pattern em questão.

A ideia é simples: em vez dos acessores setter não terem retorno (void), basta eles retornarem this:
class Person {
private String name;
private Date birthdate;
private String id;
private Load load;
private Person father;
private Person mother;

public Person() {
name = null;
birthdate = null;
id = null;
load = null;
father = null;
mother = null;
}

public String getName() {
return name;
}

public Person setName(String name) {
this.name = name;
return this;
}

public Date getBirthdate() {
return birthdate;
}

public Person setBirthdate(Date birthdate) {
this.birthdate = birthdate;
return this;
}

public Load getLoad() {
return load;
}

public Person setLoad(Load load) {
this.load = load;
return this;
}

public Person getFather() {
return father;
}

public Person setFather(Person father) {
this.father = father;
return this;
}

public Person getMother() {
return mother;
}

public Person setMother(Person mother) {
this.mother = mother;
return this;
}
}


Agora podemos usar uma estrutura de código similar à de Smalltalk:
Person person = new Person()
.setName(aString)
.setBirthdate(aDate)
.setId(anotherString)
.setLoad(aLoad)
.setFather(aPerson)
.setMother(anotherPerson);


[]'s
Cacilhas, La Batalema

terça-feira, 27 de janeiro de 2009

Singleton

Um design pattern bastante conhecido na engenharia de software é singleton.

Singleton é quando uma classe possui apenas uma instância e não se deseja que em uma mesma aplicação haja mais de uma.

Exemplos de classes desejadamente singleton são pools e carregadores.

Em C++ a saída para criar uma classe singleton é tornar protegido seu método construtor e criar um método getInstance para retornar a instância única:
class Loader {
protected:
Loader();

public:
~Loader();

static Loader& getInstance();
}


O método getInstance deve guardar uma referência estática para a instância:
static Loader& Loader::getInstance() {
static Loader *instance = 0;
if (!instance)
instance = new Loader();
return *instance;
}


Java utiliza a mesma abordagem, já outras linguagens, como Perl, Python e Ruby têm uma abordagem bem mais elegante.

Singleton em Python


A ideia de singleton em Python – Perl e Ruby – é usar o próprio construtor da classe para obter a instância.

Por exemplo, em vez de (Java):
Image character = Loader.getInstance().getImage("char.png");


Teremos (Python):
character = Loader().getImage("char.png")


Há três formas de implementar singleton em Python: 1implementando diretamente na classe, 2herdando um classe pai ou 3usando metaclasse (o mais divertido!).

Implementação direta na classe


Você pode implementar uma classe singleton diretamente, usando os metamétodos __new__ (construtor real) e __init__ (construtor de inicialização).

A classe ainda precisa ter um atributo de classe para armazenar a instância.

A ideia mais simples é implementar __new__ para devolver a instância em vez de uma nova a cada vez:
class Loader:

__instance = None
__initialized = False


def __new__(cls, *args, **keyw):
if cls.__instance is None:
cls.__instance = object.__new__(cls)
return cls.__instance


Repare no atributo __initialized… isso é porque ainda temos um problema: o construtor de inicialização (__init__) será chamado novamente a cada tentativa de obter a instância.

Então precisamos verificar se a inicialização já foi executada:
    def __init__(self, *args, **keyw):
if not self.__initialized:
self.__initialized = True
# Restante do método...


Pronto! Nossa classe já é singleton.

Herança


Podemos usar uma classe pai que implemente unicidade e estendê-la:
class Singleton:

__instance = None
__initialized = False

def __new__(cls, *args, **keyw):
if cls.__instance is None:
cls.__instance = object.__new__(cls)
return cls.__instance

def __init__(self, *args, **keyw):
if not self.__initialized:
self.__initialized = True
self._init(*args, **keyw)


Assim, para implementar uma classe singleton:
class Loader(Singleton):

def _init(self, *args, **keyw):
# Este será o construtor...


A vantagem desta abordagem é sua capacidade de reaproveitamento: é possível reutilizar a classe Singleton como classe pai de cada nova classe singleton.

No entanto traz dois inconvenientes: primeiro os métodos podem conflitar com métodos de outras classes pai em herança múltipla; segundo é preciso prestar atenção à implementação estranha (uso de _init em vez de __init__) e ter cuidado com a sobrescrita de métodos.

A solução para tornar isso mais transparente é usar uma metaclasse.

Metaclasse


Metaclasse é um classe cujas instâncias são classes. Vamos criar uma metaclasse cujas classes sejam singleton:
class singleton(type):

def __init__(cls, name, base, dict):
super(singleton, cls).__init__(name, base, dict)
cls.__instance = None
cls.__copy__ = lambda self: self
cls.__deepcopy__ = lambda self, memo=None: self

def __call__(cls, *args, **keyw):
if cls.__instance is None:
cls.__instance = \
super(singleton, cls).__call__(*args, **keyw)
return cls.__instance


Agora vem a beleza da metaclasse: para criar uma classe singleton basta fazer:
class Loader:
__metaclass__ = singleton


Nada mais! Todo o resto da classe pode ser implementado sem preocupações.

A única dúvida que pode ocorrer é: e se a classe tiver outra metaclasse?

É fácil resolver! Por exemplo: imagine uma classe singleton que implemente autopropriedades:
class Loader:

class __metaclass__(autoprop, singleton):
pass


**

Está aqui outra dica! Mais sobre singleton pode ser encontrado nas Reflexões de Monte Gasppa e Giulia C..

[]'s
Cacilhas, La Batalema

Mostrando o status e o branch de repositórios git no console

Com uma função de shell script e a ajuda da variável PS1 podemos fazer uma configuração bem interessante: exibir no próprio console em qual branch estamos e qual o estado dele.

Um exemplo de como fica:
Git no terminal

Esse é um screenshot do meu desktop, mostrando o repositório do tracks (um aplicativo interessante para quem pretende usar a metodologia GTD). Em amarelo, o caminho do repositório. Entre os colchetes, o branch no qual estamos, e finalmente, um * indicando se o repositório contém modificações ainda não confirmadas no repositório.

Para configurar, basta adicionar ao seu .bashrc:

function parse_git_dirty {
[[ $(git status 2> /dev/null | tail -n1) \
!= "nothing to commit (working directory clean)" \
]] && echo "*"
}

function parse_git_branch {
git branch --no-color 2> /dev/null | \
sed -e '/^[^*]/d' \
-e "s/* \(.*\)/[\1$(parse_git_dirty)]/"
}

export PS1='\u@\h \[\033[1;33m\]\w\[\033[0m\]$(parse_git_branch)$'


Visto originalmente aqui.

[]'s
- Walter Cruz

sábado, 24 de janeiro de 2009

Pyglet

Há alguns módulos em Python de interface com a biblioteca de mídia SDL, sendo o mais conhecido PyGame.

PyGame é legal, lembra a mim a antiga API gráfica do Colour BASIC do MSX (eita saudosismo!).

No entanto o Kao Félix apresentou recentemente um outro módulo menos conhecido, chamado Pyglet, que, a primeira vista, achei mais pythónica. =D

Gostaria então de sugirir dois tutoriais do Kao Félix:


Instalando Pyglet


Se você possui o EasyInstall, basta executar:
bash$ sudo easy_install -U pyglet


Primeira aplicação


Resolvi fazer minha primeira aplicação segundo as dicas do Kao Félix, mas adaptando a meu jeito próprio de programar.

Iniciaremos com o hash-bang, as peculiaridades de Python e os imports dos submódulos de Pyglet que vamos precisar:
#!/usr/bin/env python
# coding: UTF-8

from __future__ import division
__metaclass__ = type

from pyglet import app, clock, resource, sprite
from pyglet.window import key, Window


Carregando os recursos iniciais


Esta é classe singleton para carregar os recursos de mídia que precisaremos.

Fiz o seguinte: baixei a bola do Kao, mas pode também baixar daqui mesmo – preferível, para não sobrecarregar o link dele.

O arquivo de som está no pacote do KDE, mas você pode baixar daqui.

Nessa classe singleton, implementaremos o método __new__ (apenas para singleton) e __init__ para carregar as mídias.

Para carregar uma imagem usamos resource.image(). Para áudio, resource.media():
class Loader:
"""Singleton class for loading resources"""

__inst = None
__initialized = False

def __new__(cls, *args, **keyw):
if not cls.__inst:
cls.__inst = object.__new__(cls)
return cls.__inst

def __init__(self):
if not self.__initialized:
self.__initialzed = True

self.images = {}
self.sounds = {}

image = resource.image("char.png")
image.anchor_x = image.width // 2
image.anchor_y = image.height // 2
self.images["ball"] = image

self.sounds["pop"] = resource.media(
"pop.wav",
streaming=False
)


O parâmetro streaming=False indica que o arquivo de áudio deve ser completamente carregado para a memória – e não tratado como um fluxo (stream).

Gerenciando o teclado


Uma nova classe será usada para gerenciar o teclado. O construtor armazenará uma referência para a janela principal e o método handle_input() gerenciará as teclas:
class KeyHandler(key.KeyStateHandler):
"""Class for handling key events"""

def __init__(self, window):
super(KeyHandler, self).__init__()
self.window = window

def handle_input(self, dt):
speed = 320 * dt
dx, dy = 0, 0

if self[key.RIGHT]:
dx = 1
elif self[key.LEFT]:
dx = -1

if self[key.UP]:
dy = 1
elif self[key.DOWN]:
dy = -1

self.window.ball.x += dx * speed
self.window.ball.y += dy * speed


Repare que nosso objeto window terá um atributo ball, que é um sprite.

Agora nosso sprite


Vamos criar agora uma classe que estende sprite.Sprite, a classe de sprite de Pyglet.

O único método que implementaremos será o construtor, que buscará em Loader a imagem que desejamos:
class Ball(sprite.Sprite):
"""Sprite that's a ball"""

def __init__(self, *args, **keyw):
super(Ball, self).__init__(
Loader().images["ball"],
*args, **keyw
)


Janela principal


Finalmente a aplicação!

Por um mal hábito adquirido programando Tkinter, tenho o hábito de usar a mesma classe para aplicação e janela principal, porém você não precisa fazer esse bacalhau isso!

No entanto vou mostrar aqui da forma como estou habituado.

O construtor:
  • ajustará o título da janela (set_caption());
  • criará uma nova bola (classe Ball);
  • registrará o manipulador de eventos de teclas (push_handlers());
  • e registrará o método handle_input() do manipulador de eventos de teclas para execução periódica (clock.schedule_interval()).

class MainApplication(Window):
"""Main window and application"""

def __init__(self):
super(MainApplication, self).__init__()
self.set_caption("Teste de movimento")

self.ball = Ball(x=300, y=240)

handler = KeyHandler(self)
self.push_handlers(handler)
clock.schedule_interval(handler.handle_input, 1/60)


Manipulando outros eventos


Os métodos de Window que manipulam eventos têm nome iniciado por on_, seguido pelo nome do evento. Por exemplo: on_close, on_draw, on_key_press, on_key_release.

Vamos implementar on_close() para tocar o som ao sair e on_draw() para exibir o sprite:
    def on_close(self):
Loader().sounds["pop"].play()
super(MainApplication, self).on_close()

def on_draw(self):
self.clear()
self.ball.draw()


Fazendo funcionar


Para terminar, precisamos instanciar a aplicação e chamar o ciclo principal de Pyglet.

Veja que esse tipo de programação onde um módulo toma o controle e programamos os métodos que atenderão eventos caracteriza um framework.
if __name__ == "__main__":
window = MainApplication()
app.run()


Conclusão


Vemos aqui um ótimo módulo – ou melhor, framework – para criação de aplicações gráficas usando as bibliotecas SDL e OpenGL.

[]'s
Cacilhas, La Batalema

sábado, 10 de janeiro de 2009

Atributos privados onde?

Os programadores de Java e C++ pregam vigorosamente a favor de métodos e atributos privados, como se isso fosse uma grandíssima vantagem.

É um recurso… faz sentido em seu contexto, mas não traz vantagem alguma por si só – ao contrário da evangelização dos fanáticos.

De qualquer forma, o C++ não bloqueia tanto o acesso do programador quanto é pregado.

Por exemplo, voltemos lá atrás no artigo Portanto GDBM para Lua: havia uma classe GdbmObject com um descritor de arquivo de banco de dados privado.

Digamos que, por alguma razão bizarra, queiramos ter acesso direto ao descritor.

Mas o atributo é privado!

Vamos ao bacalhau:
class GdbmObjectCorrupting {
public:
bool closed;
GDBM_FILE fd;
}


Repare que os atributos públicos aqui têm o mesmo tipo e o mesmo nome dos atributos privados da classe original. Isso garantirá que os símbolos gerados sejam idênticos – e este é o truque.

Agora imagine que temos a instância obj de GdbmObject, da qual queremos acessar os atributos privados. A mágica é:
GdbmObjectCorrupting *aux =
reinterpret_cast<GdbmObjectCorrupting *>(obj);


Pronto! Já está feito o bacalhaua a mágica!

No escopo de aux, aux->fd dá acesso direto ao descritor de obj, assim como aux->closed dá acesso ao booleano closed de obj.

Agora, este artigo é uma prova de conceito! Não aconselho ninguém a fazer isso. Aliás o Kodumaro desaprova fortemente tal prática: reitero, é apenas uma prova de conceito.

[]'s
Cacilhas, La Batalema