Импортируйте все классы (или функции) во все файлы в папке, как если бы они были все в файле __init__

У меня есть папка с несколькими файлами, содержащими множество разных классов. Все они могут быть в одном большом файле, но для того, чтобы сделать его немного легче читать, я разделил его на несколько файлов в зависимости от того, к каким классам принадлежит.

Я хотел бы импортировать все классы из всех файлов в папку в файл __init__ чтобы я мог импортировать что-либо из папки, не зная, в какой файл он принадлежит.

Пример:

/kitchen
 + __init__.py
 + fridge.py
 + stove.py
 + cupboard.py

Теперь я должен сделать

from kitchen.fridge import milk

Когда я хочу сделать

from kitchen import milk

Эквивалент этого я могу пройти через __init__.py:

from kitchen.fridge import *
from kitchen.stove import *
from kitchen.cupboard import *

И тогда я могу сделать

from kitchen import milk

Но я бы хотел, чтобы все файлы находились в папке без необходимости явно указывать (чтобы файлы можно было сбрасывать там и затем использовать).

Есть ли способ сделать это?

Ответ 1

Это очень плохая идея. Если вы хотите добавить механизм для файлов, которые будут "сбрасываться там и используются", вы, вероятно, захотите разработать схему плагина и явно искать каталог плагинов (-ов).

Как вы обычно это делаете, это перебрать один или несколько каталогов плагинов с помощью os.listdir или os.walk, затем для каждого файла Python используйте importlib (или эквиваленты нижнего уровня от imp, в Python 2.x), чтобы импортировать его по пути.

Однако, если вы действительно настаиваете на том, чтобы подделывать вещи таким образом внутри пакета, вы можете сделать в основном те же самые трюки в файле __init__.py, используя os.path.dirname(__file__) в качестве каталога плагина.

И, если вы действительно настаиваете на том, чтобы сделать эквивалент from foo import * вместо import foo по пути, это так же просто или, альтернативно, вы можете использовать execfile.

Если вы не знаете, как делать эти простые вещи или как их искать в документах... то вам определенно не следует пытаться это делать. Поэтому я не буду приводить пример кода в этом случае.

Ответ 2

Явный лучше, чем неявный. Не делай этого. Вы можете, конечно, взломать что-то вместе, что в какой-то степени автоматизирует импорт. Но это действительно не стоит. Это всего лишь одна дополнительная строка на добавленный файл в __init__.py и все готово. Простые решения лучше, если вы не получите многого из более сложного, что, конечно же, не так.

Ответ 3

Нет, нет. Кроме того, вы не должны import *, но в __init__.py явно. Кстати, этот способ разделения модулей является обычным явлением и хорошей практикой.

import * допустим, если вы также определяете атрибут __all__ в каждом модуле, но нет никакой реальной выгоды от этого, и он имеет тенденцию нарушать анализаторы кода.

Ответ 4

import os, sys

dir_path = os.path.dirname(os.path.abspath(__file__))
files_in_dir = [f[:-3] for f in os.listdir(dir_path)
                if f.endswith('.py') and f != '__init__.py']
for f in files_in_dir:
    mod = __import__('.'.join([__name__, f]), fromlist=[f])
    to_import = [getattr(mod, x) for x in dir(mod)]
               # if isinstance(getattr(mod, x), type)]  # if you need classes only

    for i in to_import:
        try:
            setattr(sys.modules[__name__], i.__name__, i)
        except AttributeError:
            pass