Monkey patch
Monkey patch là một kỹ thuật trong Python (và các ngôn ngữ động khác), dùng để thay đổi hoặc ghimở đèrộng hành vi của một hàm, phươngmethod, thức,class, hoặc classmodule sautại khi nóthời đãiểm runtime (lúc chương trình đang chạy) mà không sửa mã gốc.
Nó được định nghĩa, mà khôdùng cầnkhi:
-
Không thể/chưa thể sửa
filemã nguồn gốc. -
Muốn mở rộng thư viện bên thứ 3
-
Override tạm thời một behavior
Nói đơn giản:
Bạn thay thế một hàm hoặc class trong thư viện gốc bằng hàm của bạn – ngay lúc chương trình đang chạy!
Cấu trúc cơ bản
# Module gốc (giả sử không thể sửa)
class Animal:
def speak(self):
return "Gâu gâu"
# Monkey patch hàm speak
def meow(self):
return "Meo meo"
Animal.speak = meow
# Test
a = Animal()
print(a.speak()) # 👉 Meo meo
Ví dụ dễvới hiểmodule tiêu chuẩn Python
Giả sử bạn cómuốn override math.sqrt
để log mỗi lần gọi:
import math
original_sqrt = math.sqrt
def logged_sqrt(x):
print(f"√{x} was called")
return original_sqrt(x)
math.sqrt = logged_sqrt
print(math.sqrt(9)) # 👉 log + 3.0
Monkey patch method của class
class User:
def greet(self):
return "Hello"
def custom_greet(self):
return "Xin chào!"
User.greet = custom_greet
u = User()
print(u.greet()) # 👉 Xin chào!
Monkey patch trong unit test
Rất phổ biến khi test cần thay thế tạm hàm nhưgọi vầy:API, DB, hoặc logic tốn thời gian.
#import trongmyapp.utils
payment_entry/payment_entry.pyoriginal = myapp.utils.get_current_time
def hello(fake_time():
print(return "Hello2025-01-01"
frommyapp.utils.get_current_time VHTerp")= fake_time
BạCách hiện khôngđại muốn(với sửa trực tiếp file, bạn làm như vầy trong app của bạn:unittest.mock
)
#from trongunittest.mock app/patches/my_patch.pyimport defpatch
custom_hello(with patch('myapp.utils.get_current_time', return_value="2025-01-01"):
print(myapp.utils.get_current_time()) # 👉 2025-01-01
Kỹ thuật monkey patch nâng cao
- Patch theo điều kiện
if settings.DEBUG:
module.func = debug_version
else:
module.func = prod_version
2. Chỉ patch một instance (không toàn bộ class)
import types
class A:
def say(self): return "HelloHello"
froma My= AppA()
👋a.say = types.MethodType(lambda self: "Xin chào", a)
print(a.say()) # 👉 Xin chào
Monkey patch và thư viện bên thứ 3
Ví dụ override hàm trong thư viện requests:
import requests
_original_get = requests.get
def my_get(*args, **kwargs):
print(f"GET called: {args[0]}")
defreturn patch():_original_get(*args, from**kwargs)
payment_entry import payment_entry
payment_entry.hellorequests.get = custom_hellomy_get