Blog em português onde relato a minha aprendizagem de Python. Sendo um blog, ele deve ser lido de baixo para cima e é escrito orientado a uma audiência com alguns conhecimentos de programação. Não tentando ser uma fonte exaustiva de conhecimento sobre Python, pode, no entanto, servir como crash course a esta linguagem.

Thursday, July 16, 2009

Métodos estáticos e Decorators

No último post sobre programação orientada a objectos esequeci-me de referir como declarar métodos static.
Para declarar métodos static, deve-se usar a função built-in staticmethod e deve ser usado da seguinte forma:
class AClass(object):
  def someStaticMethod():
     print 'i am static'
  someStaticMethod = staticmethod(someStaticMethod)

Na realidade, a única diferença entre um método static e um "normal" é que o static não recebe como primeiro argumento o valor do self. Como noutras linguagens, o método static pode ser chamado sobre uma instância dessa classe ou sobre a sua classe.

No entanto, esta forma de definir métodos não é muito simpática. Para resolver isso, o Python suporta um mecanismo adicional, decorators, que irei descrever de seguida.
Um decorator é algo que deve ser posto imediatamente antes da definição do método e tem a forma @nomeDoDecorator
de uma forma geral, @expressao avalia a expressao (que tem de ser um nome, ou uma chamada a funcao), associa esse valor a uma variável temporária (chamemos-lhe __aux) e logo a seguir à avaliação do def

que tem de aparecer a seguir ao decorator, a expressão f = __aux(f) é executada, onde f é o nome posto no def.
Este mecanismo permite uma forma muito simples de contornar a verbosidade da definição de métodos estáticos. Assim:
class AClass(object):
  @staticmethod

  def someStaticMethod():
     print 'i am static'
  
No entanto, este mecanismo pode ser usado em qualquer função, seja ela um método de uma classe ou não. É inclusivé possível criar novos decorators (que são simplesmente funções de ordem superior).
Veja-se um exemplo onde se cria um decorator que faz com que a docstring associda a uma função seja impressa no momento da sua definição. (Exemplo de Python in a Nutshell - Alex Martelli)
def showdoc(f):
  if f.__doc__:
    print '%s: %s' % (f.__name__, f.__doc__)
  else
    print '%s: No docstring!' % f.__name__
  return f




@showdoc
def f1: "a docstring"


@docstring

def f2(): pass

 Quando f1 é definido, a string "f1: a docstring" é impressa. Quando f2 é definido "f2: No docstring!" é impresso.