我正在尝试通过使用importlib.reload重新加载模块来在运行时动态更新代码。但是,我需要在执行模块代码之前设置一个特定的模块变量。我可以在重新加载后轻松地将其设置为属性,但每个模块都已经执行了它的代码(例如,定义了它的默认参数)。
一个简单的例子:
# module.py
def do():
try:
print(a)
except NameError:
print('failed')
# main.py
import module
module.do() # prints failed
module.a = 'succeeded'
module.do() # prints succeeded
所需的伪代码:
import_module_without_executing_code module
module.initialise(a = 'succeeded')
module.do()
有没有办法控制模块命名空间初始化(比如使用元类的类)?
答案 0 :(得分:1)
除了交互式调试之外,使用reload
通常不是一个好主意。例如,它可以轻松创建两个module.A
类型的对象不是同一类型的情况。
你想要的是execfile
。传递一个全局字典(你不需要一个显式的本地词典)来保持每个执行被隔离;你提前存放的任何东西就像预先设置的那样"你想要的变量。如果你想要一个真实的"模块接口更改,您可以拥有一个包装器模块,该模块从您更改的文件中调用(或仅作为属性保存)最近加载的函数。
当然,由于您使用的是Python 3,因此您必须使用one of the replacements for execfile
。
答案 1 :(得分:0)
严格地说,我不相信有一种方法可以在Python中本地描述你所描述的内容。但是,假设您拥有要导入的模块,那么需要一些初始化输入的Python模块的常用方法是使用init
函数。
如果您只需要设置一些内部变量,例如上面示例中的a
,那就很简单:只需声明一些模块全局变量并将其设置在init
函数中:
<强>模块:强>
## mymodule.py
a = None
def do():
print(a)
def init(_a):
global a
a = _a
主要强>
## main.py
import mymodule
mymodule.init(123)
mymodule.do()
mymodule.init('foo')
mymodule.do()
<强>输出:强>
123
foo
如果您需要实际重新定义某些函数,那么事情会变得棘手,因为某些动态内部函数依赖于您提供的输入。这是一个借鉴https://stackoverflow.com/a/1676860的解决方案。基本上,我们的想法是通过使用魔术变量__name__
索引到系统模块字典sys.modules
来获取对当前模块的引用,然后定义或覆盖需要它的函数。我们可以在本地将函数定义为内部函数,然后将它们添加到模块中:
<强>模块:强>
## mymodule.py
import sys
def init(a):
current_module = sys.modules[__name__]
def _do():
try:
print(a)
except NameError:
print('failed')
current_module.do = _do