我在某个路径中有一个模块。我想创建一个与模块具有相同属性的类(以便可以与模块相同的方式使用它),但是在访问属性之前执行一些自定义操作,例如重新加载模块。
def get_method_with_extra(method_name, module):
def method_with_extra(self, *args):
imp.reload(module)
func_to_call = getattr(module, method_name)
func_to_call(*args)
return method_with_extra
class tester():
def __init__(self, module_path):
self.module = imp.load_source('module', module_path)
method_list = [func for func in dir(self.module) if
callable(getattr(self.module, func))]
for method_name in method_list:
method_with_extra = get_method_with_extra(method_name,
self.module)
setattr(type(self), method_name, method_with_extra)
因此,例如,如果模块有一个名为“ Parse”的方法,我希望测试器的一个实例-tess-也要拥有它,并且对于我来说,我可以调用tess.parse()来重新加载内部模块,然后调用模块的parse()。相反,我收到此错误:
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "<string>", line 4, in __init__
AttributeError: attribute '__call__' of 'namespace#' object is read-only
答案 0 :(得分:0)
如果允许您更改目标模块的源代码,并且它足够小,我认为这里最干净的解决方案是将其重写为类。然后导入该类,从该类继承并进行自定义。
还请注意,Python中的重新加载模块有很多警告,更多的是在Python shell中玩,而不是在生产代码中。
根据您在评论中所说的内容,我对您的代码做了一些更改。我使用importlib
是因为不推荐使用模块imp。还要注意,“猴子补丁”(这就是所谓的这种技术,您想在代码中创建运行时补丁)始终与目标代码紧密结合。有了更改,您的补丁代码很容易破解。
我写了两个文件module.py
和test_module.py
:
#-----------
# module.py
a = 100
b = 200
# returns something
def sum3(x,y):
return x + y + 3
# does something
def print_a_b():
global a
print(a,b)
a = a + 1 # test module reloads. If ok, "a" remains 100
#----------------
# test_module.py
import module
import importlib as imp
def get_method_with_extra(method_name, module):
def method_with_extra(self, *args):
imp.reload(module) # comment to see that "a" increases
func_to_call = getattr(module, method_name)
if args: # function may not have args
return func_to_call(*args)
else: # function may not have args
return func_to_call()
return method_with_extra
class tester():
def __init__(self, module_path):
self.module = imp.import_module('module', module_path)
method_list = [func for func in dir(self.module)
if callable(getattr(self.module, func))]
for method_name in method_list:
#print(method_name)
method_with_extra = \
get_method_with_extra(method_name, self.module)
setattr(type(self), method_name, method_with_extra)
t = tester('.')
print(t.sum3(1,2))
t.print_a_b()
t.print_a_b() # checking for the reload, "a" should be 100