Monkey Patching refers to the practice of dynamically changing or modifying a class or module's behavior during runtime. This technique can be used to fix bugs, add new features, or extend functionality without altering the original code directly.
1. Basic Monkey Patching of a Function
Copy
# Original function
def greet(name):
return f"Hello, {name}"
# Monkey patching the function
def new_greet(name):
return f"Hi, {name}"
greet = new_greet # Replace the original function with the new one
# Test the patched function
print(greet("John")) # Output: Hi, John
2. Monkey Patching a Method of a Class
Copy
class Dog:
def speak(self):
return "Woof"
# Monkey patch the speak method
def new_speak(self):
return "Bark"
Dog.speak = new_speak # Replace the speak method
# Test the patched method
dog = Dog()
print(dog.speak()) # Output: Bark
3. Monkey Patching a Module Function
Copy
4. Monkey Patching for Logging
Copy
5. Monkey Patching for Debugging
Copy
6. Monkey Patching to Extend Behavior
Copy
7. Monkey Patching to Handle Errors
Copy
8. Monkey Patching with a Wrapper
Copy
9. Monkey Patching a Class Constructor
Copy
10. Monkey Patching for Performance
Copy
Notes:
Caution: While monkey patching is powerful, it can also lead to maintenance challenges, especially when debugging or upgrading libraries. It can cause unexpected behaviors if not used carefully.
Use Cases: Monkey patching is often used in testing, bug fixes, and adding features to third-party libraries without modifying their source code.
Alternative: Instead of monkey patching, consider subclassing or using decorators for more controlled modifications.
import math
# Original function
print(math.sqrt(16)) # Output: 4.0
# Monkey patch the sqrt function
def new_sqrt(x):
return x ** 0.5
math.sqrt = new_sqrt # Replace the original sqrt function
# Test the patched function
print(math.sqrt(16)) # Output: 4.0 (though the implementation has changed)
import time
# Original function
def sleep(seconds):
time.sleep(seconds)
# Monkey patch sleep function to add logging
def new_sleep(seconds):
print(f"Sleeping for {seconds} seconds")
time.sleep(seconds)
time.sleep = new_sleep # Replace the sleep function
# Test the patched sleep function
time.sleep(2) # Output: Sleeping for 2 seconds
# Original function
def add(a, b):
return a + b
# Monkey patch to add debugging
def debug_add(a, b):
print(f"Adding {a} and {b}")
return a + b
add = debug_add # Replace the add function
# Test the patched add function
print(add(2, 3)) # Output: Adding 2 and 3, 5
class Car:
def drive(self):
return "Driving..."
# Monkey patch to add more functionality
def new_drive(self):
original_behavior = "Driving..."
return original_behavior + " Fast!"
Car.drive = new_drive # Replace the drive method
# Test the patched method
car = Car()
print(car.drive()) # Output: Driving... Fast!
# Original function
def divide(a, b):
return a / b
# Monkey patch to handle division by zero
def safe_divide(a, b):
if b == 0:
return "Error: Division by zero"
return a / b
divide = safe_divide # Replace the divide function
# Test the patched function
print(divide(10, 0)) # Output: Error: Division by zero
print(divide(10, 2)) # Output: 5.0
def original_function(x):
return x * 2
# Wrapper function to log the arguments
def wrapper(func):
def inner(x):
print(f"Calling function with argument {x}")
return func(x)
return inner
# Monkey patch the original function with the wrapper
original_function = wrapper(original_function)
# Test the patched function
print(original_function(5)) # Output: Calling function with argument 5, 10
class MyClass:
def __init__(self, value):
self.value = value
# Monkey patch to log constructor calls
def new_init(self, value):
print(f"Initializing MyClass with value: {value}")
self.value = value
MyClass.__init__ = new_init # Replace the constructor
# Test the patched constructor
obj = MyClass(10) # Output: Initializing MyClass with value: 10
import time
# Original function
def slow_function():
time.sleep(2)
return "Done"
# Monkey patch to speed up the function for testing
def fast_function():
return "Done"
slow_function = fast_function # Replace slow_function with fast_function
# Test the patched function
print(slow_function()) # Output: Done (without the delay)