Подтвердить что ты не робот

Импорт классов из разных файлов в подкаталог

Здесь структура, с которой я работаю:

directory/
          script.py
          subdir/
                 __init__.py
                 myclass01.py
                 myclass02.py

Что я хочу сделать, это импортировать в script.py классы, определенные в myclass01.py и myclass02.py. Если я это сделаю:

from subdir.myclass01 import *

Он отлично работает для класса, определенного в myclass01.py. Но с этим решением, если в subdir есть несколько классов, определенных в разных файлах, и я хочу их импортировать, мне пришлось бы набирать одну строку для каждого файла. Для этого должен быть ярлык. Я пробовал:

from subdir.* import *

Но это не сработало.

EDIT: вот содержимое файлов:

Это __init__.py (используя __all__, как предлагал Апалала):

__all__ = ['MyClass01','MyClass02']

Это myclass01.py:

class MyClass01:
    def printsomething():
        print 'hey'

Это myclass02.py:

class MyClass02:
    def printsomething():
        print 'sup'

Это script.py:

from subdir import *
MyClass01().printsomething()
MyClass02().printsomething()

Это трассировка, которую я получаю, когда пытаюсь запустить script.py:

File "script.py", line 1, in <module>
    from subdir import *
AttributeError: 'module' object has no attribute 'MyClass01'
4b9b3361

Ответ 1

Хотя имена, используемые там, отличаются от того, что показано в структуре справочника вопросов, вы можете использовать мой ответ на вопрос под названием Namespacing и classes. Показанный там __init__.py также допустил бы, чтобы текст usepackage.py script был записан таким образом (package отображается в subdir в вашем вопросе и Class1 до myclass01 и т.д.):

from package import *

print Class1
print Class2
print Class3

Версия (обновлено):

К сожалению, код в моем другом ответе не совсем делает то, что вы хотите - он только автоматически импортирует имена любых подмодулей пакетов. Чтобы импортировать именованные атрибуты из каждого подмодуля, требуется еще несколько строк кода. Здесь измененная версия пакета __init__.py file (который также работает в Python 3.4.1):

def _import_package_files():
    """ Dynamically import all the public attributes of the python modules in this
        file directory (the package directory) and return a list of their names.
    """
    import os
    exports = []
    globals_, locals_ = globals(), locals()
    package_path = os.path.dirname(__file__)
    package_name = os.path.basename(package_path)

    for filename in os.listdir(package_path):
        modulename, ext = os.path.splitext(filename)
        if modulename[0] != '_' and ext in ('.py', '.pyw'):
            subpackage = '{}.{}'.format(package_name, modulename) # pkg relative
            module = __import__(subpackage, globals_, locals_, [modulename])
            modict = module.__dict__
            names = (modict['__all__'] if '__all__' in modict else
                     [name for name in modict if name[0] != '_'])  # all public
            exports.extend(names)
            globals_.update((name, modict[name]) for name in names)

    return exports

if __name__ != '__main__':
    __all__ = ['__all__'] + _import_package_files()  # '__all__' in __all__

В качестве альтернативы вы можете поместить указанное выше в отдельный файл .py-модуля в каталог пакета и использовать его из пакета __init__.py следующим образом:

if __name__ != '__main__':
    from ._import_package_files import *  # defines __all__
    __all__.remove('__all__')  # prevent export (optional)

Независимо от того, что вы называете файлом, это должно быть то, что начинается с символа подчеркивания _, поэтому он не рекурсивно пытается import.

Ответ 2

Ваш лучший вариант, хотя, вероятно, не самый лучший стиль, заключается в том, чтобы импортировать все в пространство имен пакетов:

# this is subdir/__init__.py
from myclass01 import *
from myclass02 import *
from myclass03 import *

Затем в других модулях вы можете импортировать то, что хотите прямо из пакета:

from subdir import Class1

Ответ 3

Я знаю, что прошло пару месяцев с момента ответа на этот вопрос, но я искал то же самое и перебегал через эту страницу. Я был не очень доволен выбранным ответом, поэтому в итоге я написал свое собственное решение и думал, что поделюсь им. Вот что я придумал:

# NOTE: The function name starts with an underscore so it doesn't get deleted by iself
def _load_modules(attr_filter=None):
    import os

    curdir = os.path.dirname(__file__)
    imports = [os.path.splitext(fname)[0] for fname in os.listdir(curdir) if fname.endswith(".py")]

    pubattrs = {}
    for mod_name in imports:
        mod = __import__(mod_name, globals(), locals(), ['*'], -1)

        for attr in mod.__dict__:
            if not attr.startswith('_') and (not attr_filter or attr_filter(mod_name, attr)):
                pubattrs[attr] = getattr(mod, attr)

    # Restore the global namespace to it initial state
    for var in globals().copy():
        if not var.startswith('_'):
            del globals()[var]

    # Update the global namespace with the specific items we want
    globals().update(pubattrs)

# EXAMPLE: Only load classes that end with "Resource"
_load_modules(attr_filter=lambda mod, attr: True if attr.endswith("Resource") else False)
del _load_modules # Keep the namespace clean

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

Ответ 4

Я использую этот простой способ:

  • добавьте каталог в системный путь, затем
  • import module или from module import function1, class1 в этом каталоге.

обратите внимание, что module - это не что иное, как имя вашего файла *.py без части расширения.

Вот общий пример:

import sys
sys.path.append("/path/to/folder/")
import module # in that folder

В вашем случае это может быть примерно так:

import sys
sys.path.append("subdir/")
import myclass01
# or
from myclass01 import func1, class1, class2 # .. etc

Ответ 5

from subdir.* import *

Вы не можете использовать '*' таким образом непосредственно после оператора 'from'. Вам нужно импортировать импорт. Пожалуйста, ознакомьтесь с документацией Python по импорту и пакетам.