Модуль "Утиная печать" подводных камней? - PullRequest
2 голосов
/ 24 февраля 2010

Я только начал экспериментировать с новой техникой, которую я назвал (на данный момент, по крайней мере) «модульная утка».

Пример:

Основной модуль

import somepackage.req  ## module required by all others
import abc
import Xyz

Модуль abc

__all__=[]

def getBus():
    """ Locates the `req` for this application """
    for mod_name in sys.modules:
        if mod_name.find("req") > 0:
            return sys.modules[mod_name].__dict__["Bus"]
    raise RuntimeError("cannot find `req` module")

Bus=getBus()

В модуле abc Мне не нужно явно import req: это может быть где угодно в иерархии пакетов. Конечно, это требует некоторой дисциплины ...

С помощью этой техники легко перемещать пакеты внутри иерархии.

Есть ли подводные камни, ожидающие меня? например переход на Python 3K

Обновлено : после еще одного тестирования я решил вернуться к вставке зависимостей пакетов непосредственно в sys.path.

Ответы [ 3 ]

4 голосов
/ 24 февраля 2010

Могут быть импортированы все виды модулей, которые содержат «req», и вы не знаете, действительно ли это модуль, который вы ищете:

>>> import urllib.request
>>> import tst
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "tst.py", line 12, in <module>
    Bus=getBus()
  File "tst.py", line 9, in getBus
    return sys.modules[mod_name].__dict__["Bus"]
KeyError: 'Bus'

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

1 голос
/ 24 февраля 2010

Эта техника опасна и подвержена ошибкам. Он может работать с вашими тестами до того дня, когда кто-то импортирует новый something.req и получит непонятную удаленную ошибку. (Это в лучшем случае; текущая реализация будет переходить на многие другие модули.) Если вы реструктурируете пакеты, то в это время достаточно просто изменить ваш код в автоматическом режиме без какого-либо использования магии. Python позволяет делать все виды волшебных, динамичных вещей, но это не значит, что мы должны.

0 голосов
/ 24 февраля 2010

Я думаю, что это больше похоже на утку. Я также рекомендовал бы использовать более уникальный идентификатор, чем «Шина»

def getBus():
    """ Locates the Bus for this application """
    for mod in sys.modules.values():
        if hasattr(mod, 'Bus') and type(mod.Bus) is...: # check other stuff about mod.Bus
            return mod.Bus
    raise RuntimeError("cannot find Bus")
...