Monkey patching is a powerful โ but sometimes risky โ feature in Python that allows you to modify or extend the behavior of libraries, modules, or classes at runtime, without changing their source code.
Letโs break it down clearly ๐
๐น 1. Definition
Monkey patching means dynamically changing or extending code (like methods, functions, or classes) while a program is running.
In other words:
- You “patch” (modify) an existing class or module.
- You donโt edit the original source file.
- The changes apply immediately at runtime.
๐งฉ Example (Simple Explanation)
Letโs say you have a built-in class or library method you want to change temporarily.
class Dog:
def bark(self):
return "Woof!"Normally:
dog = Dog()
print(dog.bark())Output:
Woof!Now, you can monkey patch this class by redefining its method at runtime:
def new_bark(self):
return "Meow!" # ๐ฑ A dog meowing? Monkey patched!
Dog.bark = new_bark # Monkey patch applied
dog = Dog()
print(dog.bark())Output:
Meow!โ
Youโve successfully changed the behavior of the Dog class without modifying its source code.
Thatโs monkey patching.
๐น 2. Where Itโs Commonly Used
Monkey patching is often used when:
- You want to fix a bug or add functionality in a third-party library.
- You need to mock or override behavior for testing.
- You want to temporarily inject custom behavior (e.g., logging, debugging).
๐น 3. Example: Patching a Built-in Library Function
Letโs patch Pythonโs built-in time.sleep() function so it doesnโt actually wait.
import time
def fast_sleep(seconds):
print(f"Skipping sleep for {seconds} seconds")
# Monkey patch time.sleep
time.sleep = fast_sleep
print("Start")
time.sleep(5)
print("End")Output:
Start
Skipping sleep for 5 seconds
Endโ
You replaced time.sleep() with your own function at runtime โ no waiting time!
๐น 4. Example: Monkey Patching for Unit Testing
Monkey patching is commonly used in testing to simulate dependencies or isolate functions.
Example: Patch a function that makes an API call to avoid real network requests.
# app.py
import requests
def get_user():
response = requests.get("https://api.example.com/user")
return response.status_codeโ Test with Monkey Patching
# test_app.py
import app
def mock_get(url):
class MockResponse:
status_code = 200
return MockResponse()
# Monkey patch requests.get
import requests
requests.get = mock_get
print(app.get_user()) # Should print 200 (mocked)Output:
200โ
No real HTTP request was made โ we patched requests.get() with a fake version.
๐น 5. Example: Monkey Patching a Method in a Module
Letโs say we have a math library that multiplies two numbers, but we want to force it to add instead.
import math
def fake_multiply(x, y):
return x + y
math.prod = fake_multiply # Monkey patch math.prod
print(math.prod([2, 3])) # Using patched versionOutput:
5โ We changed the behavior of a standard library method on the fly.
๐น 6. Monkey Patching vs Normal Overriding
| Feature | Monkey Patching | Overriding (Subclassing) |
|---|---|---|
| When Done | At runtime (dynamically) | At definition time |
| Source Code Modified? | โ No | โ Yes (in subclass) |
| Affects Original Class? | โ Yes | โ No (affects only subclass) |
| Safety | Risky (may cause side effects) | Safe and explicit |
| Use Case | Patching 3rd-party code temporarily | Extending own classes |
โ Monkey patching directly modifies the original class or module.
๐น 7. Caution โ When Not to Use Monkey Patching
Monkey patching can be dangerous if not handled carefully.
โ ๏ธ Drawbacks:
- โ Can make code unpredictable or hard to debug.
- โ Updates to the original library may break your patch.
- โ Difficult for new developers to understand whatโs happening.
- โ Can lead to naming conflicts or infinite loops if done incorrectly.
โ Use it only when:
- You canโt modify the original code (e.g., external library).
- Youโre writing temporary patches or tests.
๐น 8. Example: Safe Monkey Patching with Context
You can use context managers to apply a monkey patch temporarily.
import time
from unittest.mock import patch
def custom_sleep(seconds):
print(f"Fake sleep for {seconds} seconds")
print("Before patching:")
time.sleep(2)
with patch("time.sleep", custom_sleep):
print("\nInside patch:")
time.sleep(5)
print("\nAfter patching:")
time.sleep(2)Output:
Before patching:
(Waits 2 seconds)
Inside patch:
Fake sleep for 5 seconds
After patching:
(Waits 2 seconds)โ
unittest.mock.patch() allows temporary monkey patching, automatically restoring the original behavior.
๐น 9. Real-World Example โ Flask / Django
Many frameworks like Flask, Django, and gevent use monkey patching internally.
Example:
from gevent import monkey
monkey.patch_all()โ
This replaces Pythonโs standard libraries (socket, thread, etc.) with non-blocking versions, enabling asynchronous I/O without modifying your code.
๐งพ Summary Table
| Feature | Monkey Patching |
|---|---|
| Definition | Modifying or extending code at runtime without changing the source |
| How It Works | Reassign or replace methods/functions dynamically |
| When Used | To fix bugs, add temporary behavior, or for testing |
| Common Use Cases | Mocking API calls, debugging, patching 3rd-party libraries |
| Risk | Can break code if library updates or if used carelessly |
| Safer Alternative | Subclassing or using unittest.mock.patch() |
โ In short:
Monkey patching is the practice of dynamically modifying a module or class at runtime โ
often used for testing, debugging, or fixing behavior without touching the original source code.
๐งฉ Final Example (Quick Recap)
class Car:
def drive(self):
return "Driving normally"
def turbo_drive(self):
return "Driving at turbo speed!"
Car.drive = turbo_drive # ๐ Monkey patch
car = Car()
print(car.drive())Output:
Driving at turbo speed!โ
The method drive() was replaced at runtime โ
and thatโs exactly what Monkey Patching means in Python.
