Nano Hash - криптовалюты, майнинг, программирование

Как импортировать элементы всех модулей в пакете?

Я разрабатываю пакет с файловой структурой, подобной следующей:

test.py
package/
    __init__.py
    foo_module.py
    example_module.py

Если я вызываю import package в test.py, я хочу, чтобы модуль пакета выглядел примерно так:

>>> vars(package)
mapping_proxy({foo: <function foo at 0x…}, {example: <function example at 0x…})

Другими словами, я хочу, чтобы члены всех модулей в package находились в пространстве имен package, и я не хочу, чтобы сами модули находились в пространстве имен. package не является дополнительным пакетом.

Скажем, мои файлы выглядят так:

foo_module.py:

def foo(bar):
    return bar

example_module.py:

def example(arg):
    return foo(arg)

test.py:

print(example('derp'))

Как структурировать операторы импорта в test.py, example_module.py и __init__.py для работы вне каталога пакета (т.е. test.py) и внутри самого пакета (т.е. foo_module.py и example_module.py)? Все, что я пробую, дает Parent module '' not loaded, cannot perform relative import или ImportError: No module named 'module_name'.

Кроме того, в качестве примечания (согласно PEP 8): «Относительный импорт для импорта внутри пакета крайне не рекомендуется. Всегда используйте абсолютный путь к пакету для всего импорта. Даже сейчас, когда PEP 328 полностью реализован в Python 2.5, его стиль явного относительного импорта активно не приветствуется; абсолютный импорт более переносим и обычно более читабелен ".

Я использую Python 3.3.


  • Просто поставил сюда вслепую, не пытаясь: а как насчет from package import *? 20.01.2013

Ответы:


1

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

Мне удалось это сделать, адаптировав кое-что, что я использовал в Python 2, для автоматического импорта подключаемых модулей, чтобы они также работали в Python 3.

Вкратце, вот как это работает:

  1. Файл __init__.py пакета импортирует все остальные файлы Python в том же каталоге пакета, за исключением тех, чьи имена начинаются с символа '_' (подчеркивание).

  2. Затем он добавляет любые имена в пространстве имен импортированного модуля к имени модуля __init__ (которое также является пространством имен пакета). Обратите внимание, что мне пришлось сделать модуль example_module явно import foo из .foo_module.

Одним из важных аспектов такого подхода является осознание того, что он динамичен и не требует, чтобы имена модулей пакета были жестко закодированы в файле __init__.py. Конечно, это требует большего количества кода для выполнения, но также делает его очень универсальным и способным работать практически с любым (одноуровневым) пакетом - поскольку он автоматически импортирует новые модули при их добавлении и больше не пытается импортировать любые удаленные из каталога.

test.py:

from package import *

print(example('derp'))

__init__.py:

def _import_all_modules():
    """ Dynamically imports all modules in this package. """
    import traceback
    import os
    global __all__
    __all__ = []
    globals_, locals_ = globals(), locals()

    # Dynamically import all the package modules in this file's directory.
    for filename in os.listdir(__name__):
        # Process all python files in directory that don't start
        # with underscore (which also prevents this module from
        # importing itself).
        if filename[0] != '_' and filename.split('.')[-1] in ('py', 'pyw'):
            modulename = filename.split('.')[0]  # Filename sans extension.
            package_module = '.'.join([__name__, modulename])
            try:
                module = __import__(package_module, globals_, locals_, [modulename])
            except:
                traceback.print_exc()
                raise
            for name in module.__dict__:
                if not name.startswith('_'):
                    globals_[name] = module.__dict__[name]
                    __all__.append(name)

_import_all_modules()

foo_module.py:

def foo(bar):
    return bar

example_module.py:

from .foo_module import foo  # added

def example(arg):
    return foo(arg)
20.01.2013

2

Я думаю, вы можете получить нужные значения, не загромождая пространство имен, используя импорт стиля from module import name. Я думаю, что этот импорт будет работать для того, о чем вы просите:

Импорт для example_module.py:

from package.foo_module import foo

Импорт для __init__.py:

from package.foo_module import foo
from package.example_module import example

__all__ = [foo, example] # not strictly necessary, but makes clear what is public

Импорт для test.py:

from package import example

Обратите внимание, что это работает, только если вы используете test.py (или что-то еще на том же уровне иерархии пакетов). В противном случае вам нужно будет убедиться, что папка, содержащая package, находится в пути поиска модуля python (либо установив пакет в том месте, где Python будет его искать, либо добавив соответствующую папку в sys.path).

20.01.2013
  • +1: например, multiprocessing пакет из stdlib использует эта техника 21.01.2013
  • Если я выполняю example_module.py или __init__.py напрямую, я получаю сообщение об ошибке импорта, но test.py работает. Получение test.py, очевидно, является наиболее важным для работы, но есть ли способ (без попытки / улова) заставить работать и другие два? Полагаю, именно поэтому я разместил этот вопрос в первую очередь. 21.01.2013
  • Это также сохраняет модули в пространстве имен пакета. Теперь, когда я думаю об этом, это требование Python? 21.01.2013
  • @TylerCrompton: В общем, нет, нет хорошего способа сделать возможным запуск модуля из пакета в виде сценария. Можно поместить что-то вроде sys.path.append("..") в example_module.py, но это взлом, и он может работать некорректно (вы также можете попробовать параметр командной строки -m). Разработчики Python в значительной степени заявили, что запуск скриптов внутри пакетов - это принципиально нарушенный дизайн и что они не намерены поддерживать его когда-либо (несмотря на то, что это часто запрашивается новыми программистами Python). 21.01.2013
  • Я не уверен, что понимаю ваш вопрос о пространстве имен пакетов. Если вы поместите import package.foo_module, вы действительно получите модуль foo_module, но если вы просто import package, автоматически ничего не будет в package.foo_module (только в package.foo и package.bar). Даже from package import * (который обычно не рекомендуется) должен поступать правильно. 21.01.2013
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

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

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..