如何在自定义包中动态重载模块?
我正在尝试重新加载我写的一个自定义模块包。
我在这里看过一个其他问题,但在我的情况下似乎不太管用。
modules/__init__.py
# based on info from https://stackoverflow.com/questions/1057431/loading-all-modules-in-a-folder-in-python
import os
for module in os.listdir(os.path.dirname(__file__)):
if module[0:8] != '__init__' and module[-3:] == '.py':
if module in dir(os.path.dirname(__file__)):
reload(module)
else:
__import__(module[:-3], locals(), globals())
del module
del os
加载模块:
import modules
def loadModule(self, moduleName):
"""
Load the module with the give name
i.e. "admin" would load modules/admin.py
Args:
moduleName (str): name of the module (admin would load the admin.py file)
Returns:
boolean: success or failure of load
Raises:
None
"""
retLoadedCorrectly = False
# reload everything to dynamically pick up new stuff
reload(modules)
# grab the module
try:
m = getattr(modules, moduleName)
# save it
self.loadedModules[m.commandName] = {'module': moduleName, 'admin': m.adminOnly, 'version': m.version}
# Yay it loaded :)
retLoadedCorrectly = True
# log it
self.log('Loaded module: {0}, {1}, {2}, {3}'.format(moduleName, m.commandName, m.adminOnly, m.version))
except AttributeError:
self.log('Failed to load module: {0}'.format(moduleName), level='WARNING')
return retLoadedCorrectly
如果我调用 loadMudule("example")
,它会按预期加载并运行。然后如果我修改了 example,再次调用 loadModules 方法时,它就不会识别这些变化。
我读过关于 importlib
的内容,但那看起来只适用于 Python 3,而我使用的是 Python 2.7.6。
如果这样做不好,请随时给我指个更好的方向!
1 个回答
3
感谢dwfreed在Freenode上给我指明了方向。
这里是我最终代码的链接:https://github.com/myano/jenni/blob/master/modules/reload.py#L40
[02:27] <dwfreed> shortdudey123: basically, use the imp module to directly access python's base importer, re-import the module from the source, and then replace it in sys.modules
对于那些想知道我最终代码的人...
modules/__init__.py
:
# based on info from http://stackoverflow.com/questions/1057431/loading-all-modules-in-a-folder-in-python
# more info in my own question: http://stackoverflow.com/questions/24718759/how-do-i-dynamically-reload-a-module-in-a-custom-package
import os
import sys
import imp
# based off of https://github.com/myano/jenni/blob/master/modules/reload.py#L40
def reload(moduleName):
name = '{0}.{1}'.format(os.path.dirname(__file__).split('/')[-1:][0], moduleName)
if name in sys.modules.keys():
filePath = sys.modules[name].__file__
if filePath.endswith('.pyc') or filePath.endswith('.pyo'):
filePath = filePath[:-1]
module = imp.load_source(name, filePath)
sys.modules[name] = module
else:
pass
for module in os.listdir(os.path.dirname(__file__)):
if module[0:8] != '__init__' and module[-3:] == '.py':
name = '{0}.{1}'.format(os.path.dirname(__file__).split('/')[-1:][0], module[:-3])
__import__(module[:-3], locals(), globals())
然后是加载和重新加载的部分:
def loadModule(self, moduleName):
"""
Load the module with the give name
i.e. "admin" would load modules/admin.py
Args:
moduleName (str): name of the module (admin would load the admin.py file)
Returns:
boolean: success or failure of load
Raises:
None
"""
retLoadedCorrectly = False
# reload everything to dynamically pick up new stuff
reload(modules)
# if the module was already loaded, then we need to reload it
for cmd in self.loadedModules.keys():
if self.loadedModules[cmd]['module'] == moduleName:
modules.reload(moduleName)
# try to grab the module and get parameters from it
try:
# grab the module
m = getattr(modules, moduleName)
# save it
self.loadedModules[m.commandName] = {'module': moduleName, 'admin': m.adminOnly, 'version': m.version}
# Yay it loaded :)
retLoadedCorrectly = True
# log it
self.log('Loaded module: {0}, {1}, {2}, {3}'.format(moduleName, m.commandName, m.adminOnly, m.version))
except AttributeError, e:
self.log('Failed to load module: {0}'.format(moduleName), level='WARNING')
self.log(e, level='WARNING')
return retLoadedCorrectly