Как загрузить все модули в папку?

Может ли кто-нибудь предоставить мне хороший способ импорта целого каталога модулей?
У меня есть такая структура:

/Foo
    bar.py
    spam.py
    eggs.py

Я попытался просто преобразовать его в пакет, добавив __init__.py и выполнив from Foo import *, но он не работал так, как я надеялся.

Ответ 1

Перечислите все файлы Python (.py) в текущей папке и поместите их как переменную __all__ в __init__.py

from os.path import dirname, basename, isfile, join
import glob
modules = glob.glob(join(dirname(__file__), "*.py"))
__all__ = [ basename(f)[:-3] for f in modules if isfile(f) and not f.endswith('__init__.py')]

Ответ 3

Обновление в 2017 году: вы, вероятно, хотите использовать importlib вместо этого.

Сделайте каталог Foo пакетом, добавив __init__.py. В это __init__.py добавьте:

import bar
import eggs
import spam

Так как вы хотите, чтобы он был динамическим (что может или не может быть хорошей идеей), перечислите все py файлы с помощью list dir и импортируйте их примерно так:

import os
for module in os.listdir(os.path.dirname(__file__)):
    if module == '__init__.py' or module[-3:] != '.py':
        continue
    __import__(module[:-3], locals(), globals())
del module

Затем из своего кода сделайте это:

import Foo

Теперь вы можете получить доступ к модулям с помощью

Foo.bar
Foo.eggs
Foo.spam

и т.д. from Foo import * не очень хорошая идея по нескольким причинам, включая конфликт имен и усложнение анализа кода.

Ответ 4

Развернувшись на ответ Mihail, я считаю, что не хакерский способ (как, например, без обращения к файлам):

  • создать пустой __init__.py файл в Foo/
  • Выполнить
import pkgutil
import sys


def load_all_modules_from_dir(dirname):
    for importer, package_name, _ in pkgutil.iter_modules([dirname]):
        full_package_name = '%s.%s' % (dirname, package_name)
        if full_package_name not in sys.modules:
            module = importer.find_module(package_name
                        ).load_module(full_package_name)
            print module


load_all_modules_from_dir('Foo')

Вы получите:

<module 'Foo.bar' from '/home/.../Foo/bar.pyc'>
<module 'Foo.spam' from '/home/.../Foo/spam.pyc'>

Ответ 5

Python, включите все файлы в каталог:

Для новичков, которые просто не могут заставить его работать, кому нужны руки.

  • Создайте папку /home/el/foo и создайте файл main.py под /home/el/foo. Вставьте здесь этот код:

    from hellokitty import *
    spam.spamfunc()
    ham.hamfunc()
    
  • Создайте каталог /home/el/foo/hellokitty

  • Сделайте файл __init__.py под /home/el/foo/hellokitty и поставьте здесь этот код:

    __all__ = ["spam", "ham"]
    
  • Сделайте два файла python: spam.py и ham.py в разделе /home/el/foo/hellokitty

  • Определите функцию внутри spam.py:

    def spamfunc():
      print "Spammity spam"
    
  • Определите функцию внутри ham.py:

    def hamfunc():
      print "Upgrade from baloney"
    
  • Запустите его:

    [email protected]:/home/el/foo$ python main.py 
    spammity spam
    Upgrade from baloney
    

Ответ 6

Я сам устал от этой проблемы, поэтому я написал пакет под названием automodinit для его исправления. Вы можете получить его из http://pypi.python.org/pypi/automodinit/.

Использование выглядит так:

  • Включите пакет automodinit в ваши зависимости setup.py.
  • Замените все файлы __init__.py следующим образом:
__all__ = ["I will get rewritten"]
# Don't modify the line above, or this line!
import automodinit
automodinit.automodinit(__name__, __file__, globals())
del automodinit
# Anything else you want can go after here, it won't get modified.

Что это! Теперь импорт модуля будет устанавливать __all__ на список файлов .py [co] в модуле и также импортирует каждый из этих файлов, как будто вы набрали:

for x in __all__: import x

Поэтому эффект "from M import *" соответствует точно "import M".

automodinit счастлив работать из ZIP-архивов и поэтому является безопасным ZIP-архивом.

Найл

Ответ 7

Я знаю, что обновляю довольно старую запись, и я попытался использовать automodinit, но выяснил, что процесс настройки разбит на python3. Итак, на основе ответа Luca, я придумал более простой ответ - который может не работать с .zip - к этой проблеме, поэтому я решил поделиться этим здесь:

в модуле __init__.py от yourpackage:

#!/usr/bin/env python
import os, pkgutil
__all__ = list(module for _, module, _ in pkgutil.iter_modules([os.path.dirname(__file__)]))

и в другом пакете ниже yourpackage:

from yourpackage import *

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

Ответ 8

import pkgutil
__path__ = pkgutil.extend_path(__path__, __name__)
for imp, module, ispackage in pkgutil.walk_packages(path=__path__, prefix=__name__+'.'):
  __import__(module)

Ответ 9

Я также столкнулся с этой проблемой, и это было моим решением:

import os

def loadImports(path):
    files = os.listdir(path)
    imps = []

    for i in range(len(files)):
        name = files[i].split('.')
        if len(name) > 1:
            if name[1] == 'py' and name[0] != '__init__':
               name = name[0]
               imps.append(name)

    file = open(path+'__init__.py','w')

    toWrite = '__all__ = '+str(imps)

    file.write(toWrite)
    file.close()

Эта функция создает файл (в предоставленной папке) с именем __init__.py, который содержит переменную __all__, которая содержит каждый модуль в папке.

Например, у меня есть папка с именем Test который содержит:

Foo.py
Bar.py

Итак, в script я хочу, чтобы модули были импортированы в я буду писать:

loadImports('Test/')
from Test import *

Это будет импортировать все из Test, а файл __init__.py в Test теперь будет содержать:

__all__ = ['Foo','Bar']

Ответ 10

Ответ Anurag Uniyal с предлагаемыми улучшениями!

#!/usr/bin/python
# -*- encoding: utf-8 -*-

import os
import glob

all_list = list()
for f in glob.glob(os.path.dirname(__file__)+"/*.py"):
    if os.path.isfile(f) and not os.path.basename(f).startswith('_'):
        all_list.append(os.path.basename(f)[:-3])

__all__ = all_list  

Ответ 11

Пример Anurag с несколькими исправлениями:

import os, glob

modules = glob.glob(os.path.join(os.path.dirname(__file__), "*.py"))
__all__ = [os.path.basename(f)[:-3] for f in modules if not f.endswith("__init__.py")]

Ответ 12

Посмотрите, что ваш __init__.py определяет __all__. модули - пакеты doc говорит

Файлы __init__.py необходимы, чтобы Python рассматривал каталоги как содержащие пакеты; это делается для предотвращения каталогов с общим именем, например строки, из непреднамеренного скрытия допустимых модулей, которые появляются позже на пути поиска модуля. В простейшем случае __init__.py может быть просто пустым файлом, но он также может выполнять код инициализации для пакета или устанавливать переменную __all__, описанную ниже.

...

Единственное решение для автора пакета - предоставить явный индекс пакета. Оператор import использует следующее соглашение: если код пакета __init__.py определяет список с именем __all__, он считается списком имен модулей, которые должны быть импортированы, когда из импорта пакета * встречается. Автору пакета рекомендуется сохранить этот список в актуальном состоянии при выпуске новой версии пакета. Авторы пакета могут также решить не поддерживать его, если они не видят использования для импорта * из своего пакета. Например, файл sounds/effects/__init__.py может содержать следующий код:

__all__ = ["echo", "surround", "reverse"]

Это означало бы, что from sound.effects import * будет импортировать три названных подмодуля звукового пакета.

Ответ 13

Это лучший способ, который я нашел до сих пор:

from os.path import dirname, join, isdir, abspath, basename
from glob import glob
pwd = dirname(__file__)
for x in glob(join(pwd, '*.py')):
    if not x.startswith('__'):
        __import__(basename(x)[:-3], globals(), locals())

Ответ 14

Посмотрите на модуль pkgutil из стандартной библиотеки. Это позволит вам делать именно то, что вы хотите, пока у вас есть файл __init__.py в каталоге. Файл __init__.py может быть пустым.

Ответ 15

Я создал для него модуль, который не полагается на __init__.py (или любой другой вспомогательный файл) и заставляет меня вводить только следующие две строки:

import importdir
importdir.do("Foo", globals())

Не забудьте повторно использовать или вносить свой вклад: http://gitlab.com/aurelien-lourot/importdir

Ответ 16

Просто импортируйте их с помощью importlib и добавьте их в __all__ (действие add необязательно) в __all__ в __init__.py пакета.

/Foo
    bar.py
    spam.py
    eggs.py
    __init__.py

# __init__.py
import os
import importlib
pyfile_extes = ['py', ]
__all__ = [importlib.import_module('.%s' % filename, __package__) for filename in [os.path.splitext(i)[0] for i in os.listdir(os.path.dirname(__file__)) if os.path.splitext(i)[1] in pyfile_extes] if not filename.startswith('__')]
del os, importlib, pyfile_extes