21
Mar

Monkey Patch

Motivado pelos posts sobre paradigmas de programação escritos pelo Ronaldo Ferraz e a uma discussão sobre como alterar uma classe em tempo de execução no Python, resolvi escrever sobre esse assunto aqui no blog.



Moneky Patch é como é chamada a possibilidade de poder alterar uma classe em tempo de execução. Existem linguagens em que o Monkey Patch é muito utilizado, como o Ruby, mas é possível utilizar essa técnica em Python também.



Em Ruby para alterar uma classe basta apenas chamar a classe novamente e assim extendê-la:



Vamos criar uma classe chamada Teste:




class Teste
def oi
puts 'oi'
end
end


Vamos alterar ela. Como citei acima basta apenas recriar ela com o novo método:




class Teste
def ola
puts 'ola'
end
end


Em Ruby é permitido alterar classes nativas e métodos já existentes. Dessa forma se eu quiser adicionar um método a classe String eu posso.




class String
def conta
return self.size()
end
end


Em Python as coisas funcionam um pouco diferente. Vamos criar uma classe sem métodos chamada Teste:




>>>class Teste: pass
>>> dir(Teste)
['__doc__', '__module__']


Vamos criar uma função para adicionar futuramente como método a classe Teste




>>> def oi(self): print 'oi'


Para adicionar essa função como método da classe basta criar um atributo na classe e atribuir a função a esse atributo da seguinte maneira:




>>> Teste.oi = oi


E para confirmar que está tudo funcionando como esperado, vamos criar uma instância para a classe Teste e executar o método oi:




>>> teste = Teste()
>>> teste.oi()
oi


Outra forma de adicionarmos um método a uma classe é usando o método setattr:




>>>setattr(Teste, oi.__name__, oi)


Agora com esse conhecimento é possível, automatizar isso criando decorators ou metaclasses como num exemplo dado pelo Guido van Rossum.



Só uma observação. Diferente de Ruby, no Python não é possivel fazer monkey patch em classes built-in como str, int, list.



Vamos a um exemplo:




>>> def conta(self): print len(self)

>>> setattr(str, conta.__name__, conta)

Traceback (most recent call last):
File "", line 1, in
TypeError: can't set attributes of built-in/extension type 'str'


Para finalizar, ter o recurso do monkey patch numa linguagem é algo muito poderoso, e alguém já disse que 'com grandes poderes, vem grandes responsabilidades'. Se você alterar uma classe usando o monkey patch com um método que já existe nessa classe, isso pode ser algo bem traiçoeiro.





4 Comentários

  • eduardo willians comentou:

    Ótimo post. Acho que o caminho das letras está sendo novamente encontrado. Boa sorte ;)

  • Lauro Moura comentou:

    Esse problema de modificar métodos existentes fica mais interessante quando a classe é compartilhada com outros módulos aos quais o programador não tem acesso.

    - "Você precisa do documento XYZ".
    - "Mas lá em MNO me deram o documento ABC".
    - "Problema seu, só aceitamos XYZ"...

    PS: Van Russel ou Van Rossum? =)

  • Walter Cruz comentou:

    Van Russel? Vin Diesel? :)

    Aliás, o link sobre monkeypatch que você compartilhou no google reader é muito interessante. Abraço!

  • Andrews Medina comentou:

    Da onde eu tirei esse Russel? :-)


Deixe um comentário

Nome:

Comentário: