Поместить отдельные пакеты Python в одно и то же пространство имен?

Я разрабатываю каркас Python, в котором «аддоны» написаны как отдельные пакеты. То есть:.

import myframework
from myframework.addons import foo, bar

Теперь я пытаюсь организовать так, чтобы эти дополнения могли распространяться отдельно от базовой инфраструктуры и внедряться в пространство имен myframework.addons .

В настоящее время моим лучшим решением является следующее. Надстройка будет развернута (скорее всего, в {python_version}/site-packages/ примерно так:

fooext/
fooext/__init__.py
fooext/myframework/
fooext/myframework/__init__.py
fooext/myframework/addons/
fooext/myframework/addons/__init__.py
fooext/myframework/addons/foo.py

fooext/myframework/addons/__init__.py будет иметь код расширения пути pkgutil:

import pkgutil
__path__ = pkgutil.extend_path(__path__, __name__)

Проблема в том, что для того, чтобы это работало, PYTHONPATH должен иметь в себе fooext/, однако единственное, что у него будет, это родительский каталог установки (скорее всего, вышеупомянутый site-packages).

Решением этой проблемы является наличие дополнительного кода в myframework/addons/__init__.py, который будет проходить sys.path и найдите все модули с подпакетом myframework, в этом случае он добавляет его в sys.path и все работает.

Еще одна идея, которая у меня возникла, - записать файлы надстроек непосредственно в место установки myframework/addons/, но тогда это будет отличать разработку и развернутое пространство имен .

Есть ли лучший способ выполнить этот или, возможно, другой подход к вышеупомянутой проблеме распространения?

14 голосов | спросил Dimitri Tcaciuc 18 Jam1000000amSun, 18 Jan 2009 08:17:19 +030009 2009, 08:17:19

4 ответа


0
  

Есть ли лучший способ выполнить этот или, возможно, другой подход к вышеупомянутой проблеме распространения?

Возможно. Настройка модуля /пакета Python, как правило, сложно подделать динамически, как это, но его система объектов /классов открыта и расширяема в четко определенной форме. Когда модули и пакеты не совсем имеют функций, которые вам нужны для удобной инкапсуляции вашего проекта, вы можете использовать классы.

Например, вы можете иметь функциональность расширения в совершенно другом пакете, но позволить ему внедрять классы в базовую среду через определенный интерфейс. например. myframework /_ _ init _ _.py, содержащая базовую оболочку приложения:

class MyFramework(object):
    """A bare MyFramework, I only hold a person's name
    """
    _addons= {}
    @staticmethod
    def addAddon(name, addon):
        MyFramework._addons[name]= addon

    def __init__(self, person):
        self.person= person
        for name, addon in MyFramework._addons.items():
            setattr(self, name, addon(self))

Тогда вы могли бы иметь функциональность расширения в myexts /helloer.py, который хранит ссылку на свой «владелец» или «внешний» экземпляр класса MyFramework:

class Helloer(object):
    def __init__(self, owner):
        self.owner= owner
    def hello(self):
        print 'hello '+self.owner.person

import myframework
myframework.MyFramework.addAddon('helloer', Helloer)

Так что теперь, если вы просто «импортируете myframework», вы получите только базовую функциональность. Но если вы также «импортируете myexts.helloer», вы также получите возможность вызывать MyFramework.helloer.hello (). Естественно, вы также можете определить протоколы для аддонов для взаимодействия с базовым поведением фреймворка и друг с другом. Вы также можете делать такие вещи, как внутренние классы, которые можно переопределить подклассом фреймворка, чтобы настраивать его без необходимости исправления классов, которые могут повлиять на другие приложения, если вам нужен такой уровень сложности.

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

ответил bobince 18 Jpm1000000pmSun, 18 Jan 2009 18:01:30 +030009 2009, 18:01:30
0

Setuptools имеет возможность поиска пакетов «точек входа» (функций, объектов и т. д.) по имени. Trac использует этот механизм для загрузки своих плагинов и работает хорошо.

ответил Alec Thomas 19 Jam1000000amMon, 19 Jan 2009 08:35:28 +030009 2009, 08:35:28
0

Похоже, что то, что вам нужно, может быть выполнено довольно аккуратно с помощью ловушек импорта.

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

Когда обнаруживается, что пакет связан с загрузчиком (который может быть просто жестко запрограммирован в относительном пути при необходимости), он всегда будет использовать загрузчик, например, для загрузки всех надстроек. Преимущество этого состоит в том, что PYTHONPATH не требует никаких действий, что, как правило, стоит держать как можно короче.

Альтернативой этому является использование файлов init для перенаправления вызова импорта для субмодуля на тот, который вы хотите, чтобы он поднял, но это немного грязно.

Дополнительную информацию о хуках импорта можно найти здесь:

http://www.python.org/dev/peps/pep- 0302 /

ответил Dan 18 Jpm1000000pmSun, 18 Jan 2009 15:06:18 +030009 2009, 15:06:18
0

Существует совершенно новая настройка для пространств имен. Ознакомьтесь с упаковкой пакетов пространства имен . Короче говоря, у вас есть три варианта, в зависимости от степени обратной совместимости, которую вы хотите, чтобы ваш код был. Существует также соответствующий PEP, который заменяет упомянутые в других ответах: PEP 420 .

ответил jgbarah 24 +03002017-10-24T21:23:01+03:00312017bEurope/MoscowTue, 24 Oct 2017 21:23:01 +0300 2017, 21:23:01

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132