Я работаю над проектом, который динамически собирает классы из другого модуля и создает новые классы на основе найденных. Например, если исходный модуль имеет класс «AdaptiveFilter», создается новый класс с именем «AdaptiveFilterNode», содержащий экземпляр «AdaptiveFilter». Я добавлял эти сгенерированные классы в динамически созданный модуль (module_from_spec()
) и создал MetaPathFinder
и Loader
для расширения системы import
. Это отлично работает при импорте модуля Dynami c, например, import nodes.auto_gen
или from nodes.auto_gen import AdaptiveFilterNode
, но не работает при попытке напрямую импортировать класс, например import nodes.auto_gen.AdaptiveFilterNode
. Мне нужно иметь возможность напрямую импортировать класс, потому что сгенерированные классы должны иметь возможность выбора, что требует прямого импорта. Я считаю, что проблема в Finder, который я сделал:
class MyNodeFinder(MetaPathFinder):
def find_spec(self, fullname, path=None, target=None):
if fullname == 'nodes.auto_gen':
auto_gen_spec = = ModuleSpec('nodes.auto_gen',
MyLoader())
return auto_gen_spec
return None
Из моего ограниченного понимания системы импорта, в Finder или модуле spe c нет ничего, что сообщает системе импорта, что классы содержатся в модуле nodes.auto_gen
, пока модуль уже не будет загружен. Как я могу создать поисковик / загрузчик, который копирует стандартную систему импорта для модуля Dynami c с классами Dynami c?
EDIT : Полный пример, модуль dynamic_creator:
dynamic_creator / __ init __. Py
from importlib.machinery import ModuleSpec
from importlib.util import module_from_spec
import sys
from importlib.abc import MetaPathFinder
from importlib.abc import Loader
__version__ = '0.0.0'
class _MyWrapperClass():
wrapped_func = None
def __init__(self):
super().__init__()
def __call__(self, *args, **kwargs):
return self.wrapped_func(*args, **kwargs)
class MyFinder(MetaPathFinder):
def find_spec(self, fullname, path=None, target=None):
if fullname == 'dynamic_creator.auto_gen':
auto_node_spec = ModuleSpec('dynamic_creator.auto_gen',
MyLoader())
return auto_node_spec
return None
class MyLoader(Loader):
def create_module(self, spec):
return module_from_spec(ModuleSpec('dynamic_creator.auto_gen', None))
def exec_module(self, module):
def create_type(func):
t = type(func.__name__, (_MyWrapperClass, ), {})
t.wrapped_func = func
# Wait, you can do this?
t.__module__ = 'dynamic_creator.auto_gen'
return t
funcs_to_wrap = [
sum,
abs,
pow
]
for func in funcs_to_wrap:
setattr(module, func.__name__, create_type(func))
my_finder = MyFinder()
sys.meta_path.append(my_finder)
Тестовый сценарий:
import dynamic_creator.auto_gen # Works
from dynamic_creator.auto_gen import abs # Works
import dynamic_creator.auto_gen.pow as my_pow # Fails
EDIT : Сообщение об ошибке выглядит следующим образом:
No module named 'dynamic_creator.auto_gen.pow'; 'dynamic_creator.auto_gen' is not a package