Skip to main content

Monkey Patch | Python

  • Monkey Patch | Python

Definição

Monkey patch é a técnica de alterar dinamicamente classes, métodos ou funções em tempo de execução, sem modificar o código-fonte original onde esses elementos foram definidos.

No Python, isso é possível porque:

  • Classes são objetos mutáveis
  • Funções são objetos de primeira classe
  • A resolução de atributos ocorre em runtime
  • O binding de métodos é dinâmico

Tecnicamente, trata-se da redefinição ou injeção de atributos em objetos já carregados na memória do interpretador.


Fundamento Técnico

Quando um atributo é acessado em um objeto:

obj.metodo()

O Python realiza:

  1. Busca no __dict__ da instância
  2. Busca na classe
  3. Busca nas classes base (MRO – Method Resolution Order)

Monkey patch funciona porque é possível modificar dinamicamente o __dict__ da classe ou do módulo.


Substituindo um Método de Classe

Classe Original

class Usuario:
def saudacao(self):
return "Olá"

Aplicando Monkey Patch

def nova_saudacao(self):
return "Olá, mundo!"

Usuario.saudacao = nova_saudacao

u = Usuario()
print(u.saudacao()) # Olá, mundo!

Aqui ocorre:

  • Substituição direta do atributo saudacao na classe
  • Todas as instâncias passam a utilizar o novo comportamento

Alterando Função de um Módulo

import math

def fake_sqrt(x):
return 42

math.sqrt = fake_sqrt

print(math.sqrt(9)) # 42

Impacto:

  • Afeta todo o escopo onde o módulo foi importado
  • Pode alterar comportamento global do processo

⚠️ Isso altera o comportamento esperado da biblioteca padrão.


Adicionando Método Dinamicamente

class Produto:
pass

def calcular_desconto(self):
return 10

Produto.calcular_desconto = calcular_desconto

p = Produto()
print(p.calcular_desconto()) # 10

Nesse caso:

  • O método não existia originalmente
  • Foi injetado no namespace da classe

Monkey Patch em Instância Específica

Também é possível alterar apenas uma instância:

class Cliente:
def status(self):
return "ativo"

c1 = Cliente()
c2 = Cliente()

def status_bloqueado(self):
return "bloqueado"

c1.status = status_bloqueado.__get__(c1, Cliente)

print(c1.status()) # bloqueado
print(c2.status()) # ativo

Aqui o patch é aplicado apenas a c1.


Uso em Testes Automatizados

Ferramentas como unittest.mock permitem monkey patch controlado.

Exemplo:

from unittest.mock import patch

with patch("math.sqrt", return_value=99):
import math
print(math.sqrt(4)) # 99

Nesse caso:

  • O patch é temporário
  • É restaurado após o bloco with
  • Reduz risco de efeitos colaterais

Casos de Uso

Testes (Mocking)

Substituir dependências externas como:

  • APIs
  • Banco de dados
  • Serviços HTTP

Hotfix Temporário

Corrigir comportamento de biblioteca sem modificar código-fonte.

Instrumentação

Adicionar logging ou métricas em funções de terceiros.


Riscos e Problemas

  • Quebra de previsibilidade
  • Efeitos colaterais globais
  • Conflitos entre bibliotecas
  • Debugging complexo
  • Violação do princípio da menor surpresa

Em sistemas grandes, monkey patch pode gerar comportamento difícil de rastrear.


Alternativas Mais Seguras

Em arquiteturas robustas, recomenda-se:

  • Injeção de dependência
  • Decorators
  • Wrappers
  • Composição
  • Herança controlada
  • Strategy pattern

Monkey patch deve ser considerado uma ferramenta de baixo nível.