#python #python-3.x
#python #python-3.x
Вопрос:
Допустим, у меня есть каталог foo
, содержащий некоторые .py
файлы.
Каждый из этих файлов python имеет определенный класс Bar
.
Скажем, было вызвано три .py
файла baz.py
, qux.py
и quux.py
— затем, чтобы получить классы bar, которые я мог бы написать:
import foo.baz
import foo.qux
import foo.quux
bars = [
foo.baz.Bar,
foo.qux.Bar,
foo.quux.Bar,
]
Однако, вместо того, чтобы перечислять весь подобный импорт и все Bar
имена, я хочу заполнить bars
его программно.
То есть я хочу написать некоторый код для заполнения bars
, который не изменяется при .py
добавлении или удалении файлов из foo
каталога.
Одним из способов сделать это может быть использование Path('foo').iterdir()
для перечисления .py
файлов, но тогда как мне выполнить программирование import
строки и назвать ее Bar
класс?
Или есть какой-то совершенно другой подход для достижения этой цели?
bars = []
for py_file in the directory foo:
import foo.py_file ???
bars.append(foo.py_file.Bar) ???
Комментарии:
1. Взгляните на встроенный пакет
importlib
Ответ №1:
Вот один из подходов, использующих glob
module для сопоставления имен путей модулей, которые мы хотели бы импортировать, и importlib
‘s SourceFileLoader
для импорта.
from glob import glob
from importlib.machinery import SourceFileLoader
modules = glob('foo/*.py')
bars = list(map(lambda pathname: SourceFileLoader(".", pathname).load_module().Bar, modules))
Комментарии:
1. Я не понимаю, что
SourceFileLoader(".", ...)
это значит. Что значит передавать"."
в качествеfullname
параметраSourceFileLoader
? Будут ли какие-либо инструкции import, содержащиеся в загруженных файлах, продолжать работать правильно?
Ответ №2:
Вы можете использовать importlib
для динамического импорта модулей. Но сначала вам нужно их найти. Если вы включите foo.__init__.py
в исходный код, то тогда foo.__file__
будет это имя. Вы можете использовать это как основу вашего глобуса, но вам нужно убедиться, что вы не пытаетесь импортировать __init__.py
себя. Этот метод хорош, потому что вам не нужно беспокоиться о том, что другой бит источника импортирует то же имя модуля, но получает другой модуль в памяти.
from pathlib import Path
import importlib
import foo
def no_magic(paths):
for path in paths:
if not path.name.startswith("_"):
yield path
bars = []
for py in no_magic(Path(foo.__file__).resolve().parent.glob("*.py")):
mod = importlib.import_module(f"foo.{py.stem}", foo)
bars.append(mod.Bar)
print(bars)