我正在写一个应用程序.没有花哨的GUI:s或任何东西,只是一个普通的旧控制台应用程序.这个应用程序,让我们称之为App,需要能够在启动时加载插件.所以,很自然地,我创建了一个继承的插件类:
class PluginBase(object):
def on_load(self):
pass
def on_unload(self):
pass
def do_work(self, data):
pass
Run Code Online (Sandbox Code Playgroud)
想法是在启动时,App会遍历当前目录,包括子目录,搜索包含本身是其子类的类的模块PluginBase.
更多代码:
class PluginLoader(object):
def __init__(self, path, cls):
""" path=path to search (unused atm), cls=baseclass """
self.path=path
def search(self):
for root, dirs, files in os.walk('.'):
candidates = [fname for fname in files if fname.endswith('.py') \
and not fname.startswith('__')]
## this only works if the modules happen to be in the current working dir
## that is not important now, i'll fix that later
if candidates:
basename = os.path.split(os.getcwd())[1]
for c in candidates:
modname = os.path.splitext(c)[0]
modname = '{0}.{1}'.format(basename, modname)
__import__(mod)
module = sys.modules[mod]
Run Code Online (Sandbox Code Playgroud)
在最后一行之后,search我想以某种方式a)找到新加载的模块中的所有类,b)检查这些类中的一个或多个是否是PluginBasec的子类(如果b)实例化那些/那些类并添加到App的已加载模块列表.
我尝试了各种各样的组合issubclass,然后是一段激烈的dir时间和大约一个小时的恐慌谷歌搜索.我确实在这里找到了类似的方法,我尝试了复制粘贴,但得到一个错误,说Python不支持按文件名导入,此时我有点失去了注意力,因此,这篇文章写的.
我在我的智慧结束,所有帮助赞赏.
您可能会执行以下操作:
for c in candidates:
modname = os.path.splitext(c)[0]
try:
module=__import__(modname) #<-- You can get the module this way
except (ImportError,NotImplementedError):
continue
for cls in dir(module): #<-- Loop over all objects in the module's namespace
cls=getattr(module,cls)
if (inspect.isclass(cls) # Make sure it is a class
and inspect.getmodule(cls)==module # Make sure it was defined in module, not just imported
and issubclass(cls,base)): # Make sure it is a subclass of base
# print('found in {f}: {c}'.format(f=module.__name__,c=cls))
classList.append(cls)
Run Code Online (Sandbox Code Playgroud)
为了测试以上内容,我不得不稍微修改一下您的代码;以下是完整的脚本。
import sys
import inspect
import os
class PluginBase(object): pass
def search(base):
for root, dirs, files in os.walk('.'):
candidates = [fname for fname in files if fname.endswith('.py')
and not fname.startswith('__')]
classList=[]
if candidates:
for c in candidates:
modname = os.path.splitext(c)[0]
try:
module=__import__(modname)
except (ImportError,NotImplementedError):
continue
for cls in dir(module):
cls=getattr(module,cls)
if (inspect.isclass(cls)
and inspect.getmodule(cls)==module
and issubclass(cls,base)):
# print('found in {f}: {c}'.format(f=module.__name__,c=cls))
classList.append(cls)
print(classList)
search(PluginBase)
Run Code Online (Sandbox Code Playgroud)