Как получить путь к модулю, импортированному importlib, где был определен класс

#python-3.x #python-importlib

#python-3.x #python-importlib

Вопрос:

Есть хороший способ получить путь к модулю, в котором был определен класс, просто сделайте

 inspect.getfile(obj.__class__)
 

К сожалению, похоже, что он не работает для файлов, загруженных importlib:

 spec = importlib.util.spec_from_file_location('loaded_module', module_path)
M = importlib.util.module_from_spec(spec)
spec.loader.exec_module(M)

obj = M.MyClass()
inspect.getfile(obj.__class__)
 

результаты

   File "/nix/store/z65l1jqvxa58zzwwa3bvglb6asj4y8cv-python3-3.8.5/lib/python3.8/inspect.py", line 665, in getfile
    raise TypeError('{!r} is a built-in class'.format(object))
TypeError: <class 'loaded_module.MyClass'> is a built-in class
 

Есть идеи, как это исправить?

Ответ №1:

Ожидается inspect.getfile , что class объект (который имеет строковый __module__ атрибут, который является именем модуля) имеет свой модуль в sys.modules (где модуль можно искать по имени)

без модуля в sys.modules нем невозможно использовать эту цепочку для поиска вашего файла

чтобы поместить его в sys.modules , вы должны сделать что-то вроде:

 sys.modules[M.__name__] = M
 

но если у вас есть доступ к M объекту где-то, вы можете получить доступ .__file__ напрямую, или если у вас есть доступ к loader

в качестве альтернативы, если вы знаете, что для класса в этом файле определен какой-то метод, вы можете запросить объект code этой функции:

 >>> M.C.__init__.__code__.co_filename
t.py
 

Комментарии:

1. Интересно, может быть, я как-то неправильно инициализирую модуль, поэтому он не отображается в sys.modules ?

2. нет, ввод чего sys.modules -либо полностью отделен от низкоуровневого механизма importlib. существуют потенциальные проблемы с размещением там вещей (поскольку он глобальный, коллизии имен имеют значение, есть семантика подмодулей и т.д.)

3. В идеале я хочу вызвать inspect.getfile(self.__class__) внутри конструктора базового класса и получить файл, в котором определен дочерний класс. Но, конечно, у меня есть доступ к загрузчику, поэтому я могу организовать вещи, которые помогут getfile на более позднем этапе

4. это кажется очень странным дизайном — обычно родительские классы не должны знать о своих подклассах и обычно inspect должны использоваться только для отладки

5. Хм. Я просто хочу удалить дублирование кода. По сути, каждый модуль описывает своего рода эксперимент, и он должен генерировать журналы в отдельной директории. Схема именования фиксирована и привязана к имени файла модуля. Это очень удобно, потому что позволяет мне просто копировать файлы модуля, переименовывать их, настраивать несколько вещей и готовить модуль к запуску. Поэтому кажется очень логичным перенести эту логику в базовый класс.