我正在为斜杠框架开发一个测试装置,它需要修改
time.sleep
的行为。由于原因我无法使用 pytest,所以我正在尝试推出自己的基本猴子补丁支持。
我能够轻松地替换
time.sleep
来替换 import time
的东西,但有些东西在我的装置实例化之前就可以 from time import sleep
。到目前为止,我正在使用 gc.get_referrers
来追踪对 sleep
的任何引用,然后再替换它们:
self._real_sleep = time.sleep
for ref in gc.get_referrers(time.sleep):
if (isinstance(ref, dict)
and "__name__" in ref
and "sleep" in ref
and ref["sleep"] is self._real_sleep):
self._monkey_patch(ref)
实际上这可行,但感觉很丑陋。我确实可以访问相当当前的 python(当前为 3.11),但添加第 3 方依赖项的能力有限。是否有更好/更安全的方法来仅使用标准库方法来查找对某个事物的引用或在全局范围内修补某个事物?
您可以使用Python的
sys.modules
来全局替换time.sleep
。这包括直接导入 time.sleep
以及使用 from time import sleep
的情况。
这是代码。
import time
import sys
import gc
class TimeSleepPatch:
def __init__(self, new_sleep_func):
self._new_sleep_func = new_sleep_func
self._real_sleep = time.sleep
self._patched_modules = []
def _patch_module(self, module, attr_name):
# Replace the reference to the original time.sleep with the patched one
if hasattr(module, attr_name):
if getattr(module, attr_name) is self._real_sleep:
setattr(module, attr_name, self._new_sleep_func)
self._patched_modules.append((module, attr_name))
def patch(self):
# Patch the time module itself
time.sleep = self._new_sleep_func
# Go through all modules and replace any reference to time.sleep
for module in sys.modules.values():
if module:
self._patch_module(module, "sleep")
# Optional: Patch referrers in case any obscure reference still lingers
for ref in gc.get_referrers(self._real_sleep):
if isinstance(ref, dict):
for key, value in ref.items():
if value is self._real_sleep:
ref[key] = self._new_sleep_func
def restore(self):
# Restore the original time.sleep
time.sleep = self._real_sleep
# Restore patched modules to their original state
for module, attr_name in self._patched_modules:
setattr(module, attr_name, self._real_sleep)
self._patched_modules.clear()
# Example of a custom sleep function
def fake_sleep(duration):
print(f"Fake sleep for {duration} seconds")
# Instantiate the patcher and patch the time.sleep
patcher = TimeSleepPatch(fake_sleep)
patcher.patch()
# Test it (this will print "Fake sleep for 2 seconds")
time.sleep(2)
# Restore the original time.sleep
patcher.restore()
# Test the restored behavior (this will actually sleep)
time.sleep(2)
希望这对你有一点帮助。