Абсолютный модуль импорта в той же упаковке

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

mypkg/
   __init__.py
   a.py
   b.py

a.py содержит:

def echo(msg):
    return msg

b.py содержит:

from mypkg import a       # possibility 1, doesn't work
#import a                 # possibility 2, works
#from mypkg.a import echo  # import also fails

print(a.echo())

Бег python b.py производит ImportError: No module named mypkg на Python 2.7.6 и Python 3.3.5. Я также попытался добавить from __future__ import absolute_import в обоих случаях одна и та же проблема.

Ожидаемое:

Я ожидаю, что возможность 1 будет работать просто отлично.

Почему я хочу сделать это:

Возможность 2 менее желательна. Гипотетически, стандартная библиотека может представить пакет под названием a (вряд ли в этом случае, но вы поняли). В то время как Python 2 сначала ищет текущий пакет, Python 3+ включает абсолютные изменения импорта, поэтому сначала проверяется стандартная библиотека. Неважно, по какой причине, возможность 1 должна работать, нет? Я могу поклясться, что делал это тысячи раз раньше.

Примечание: если вы пишете сценарий, внешний по отношению к mypkg, from mypkg import a работает без проблем.

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

3 ответа

Решение

from mypkg import a это правильная форма. Не запускайте скрипты из директории пакета Python, он делает один и тот же модуль доступным, используя несколько имен, которые могут привести к ошибкам. Бежать python -m mypkg.b из каталога, который содержит mypkg вместо.

Чтобы иметь возможность работать из любого каталога, mypkg должен быть в pythonpath.

Да, это не будет работать, потому что в данный момент вы звоните print(mypkg.a.echo()), mypkg все еще загружается (mypkg.__init__ -> mypkg.b). Это потому, что Python сначала загружает родительские модули. https://docs.python.org/3/reference/import.html

Что вы можете сделать, это обернуть print(mypkg.a.echo()) в функцию:

def echo():
   mypkg.a.echo()

А потом:

import mypkg.b
mypkg.b.echo()

Или даже:

print(sys.modules['mypkg.a'].echo())

Также вы можете помочь Python найти ваш модуль:

import importlib
mypkg.a = importlib.import_module('mypkg.a')
mypkg.a.echo()

Я думаю, что проблема в том, что у вас нет ссылки на mypkg в папке mypkg. Посмотрите, что делает Python, когда я пытаюсь запустить ваш пример (используя подробный вариант):

# trying /vagrant/mypkg/mypkg.py

Вот почему он может найти модуль, потому что он не существует. Один из способов, который вы могли бы сделать, - это файл mypkg.py со строкой

import a

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

from a import echo

print(echo('message'))

Попробуй это:

import sys
import os
this_dir = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.dirname(this_dir))

from mypkg import a
print(a.echo())
Другие вопросы по тегам