У меня есть следующая файловая структура:
bot
├── LICENSE.md
├── README.md
├── bot.py # <-- file that is executed from command line
├── plugins
│ ├── __init__.py
│ ├── debug.py
│ └── parsemessages.py
├── helpers
│ ├── __init__.py
│ ├── parse.py
│ └── greetings.py
└── commands
├── __init__.py
└── search.py
bot.py при выполнении из командной строки загрузит все, что находится в каталоге plugins.
Я хочу plugins/parsemessages.py импортировать parse из каталога helpers, поэтому я делаю это:
# parsemessages.py
from ..helpers import parse
parse.execute("string to be parsed")
Я запускаю python3 bot.py из командной строки.
Я получаю следующую ошибку:
File "/home/bot/plugins/parsemessages.py", line 2, in <module>
from ..helpers import parse
ValueError: attempted relative import beyond top-level package
Поэтому я меняю две точки на одну:
# parsemessages.py
from .helpers import parse
parse.execute("string to be parsed")
... но я получаю другую ошибку:
File "/home/bot/plugins/parsemessages.py", line 2, in <module>
from .helpers import parse
ImportError: No module named 'plugins.helpers'
Как я могу заставить этот импорт работать?
Стоит отметить, что я не пытаюсь сделать здесь пакет, это обычный скрипт. При этом я не хочу возиться с sys.path - я хочу, чтобы это было чисто в использовании.
Кроме того, я хочу, чтобы parse импортировалось как parse, поэтому для приведенного выше примера я должен печатать parse.execute(), а не execute().
Я нашел эта почта и эта почта, но они начинаются с файла, который находится довольно глубоко в файловой структуре (мой находится прямо вверху). Я также нашел эта почта, но, похоже, речь идет о пакете, а не просто об обычном .py.
Какое решение здесь?
Будет ли это работать, если вы поместите __init__.py в свой каталог верхнего уровня?
@hd1: from . import parse приводит к ImportError: cannot import name 'parse'
@jnrbsn: К сожалению, это не так





Вы можете удалить точки, и это должно работать:
# parsemessages.py
from helpers import parse
parse.execute("string to be parsed")
Это, вероятно, ваше лучшее решение, если вы действительно не хотите делать это пакетом. Вы также можете вложить весь проект на один каталог глубже и назвать его как python3 foo/bot.py.
Объяснение:
Когда вы не работаете с фактически установленным пакетом, а просто импортируете данные, относящиеся к вашему текущему рабочему каталогу, все в этом каталоге считается пакетом верхнего уровня. В вашем случае bot, plugins, helpers и commands все пакеты/модули верхнего уровня. Ваш текущий рабочий каталог сам по себе является нет пакетом.
Поэтому, когда вы делаете...
from ..helpers import parse
... helpers считается пакетом верхнего уровня, потому что он находится в вашем текущем рабочем каталоге, и вы пытаетесь импортировать его из одного уровня выше этого (от вашего текущего рабочего каталога сам, который не является пакетом).
Когда ты делаешь...
from .helpers import parse
... вы импортируете относительно plugins. Итак, .helpers решается на plugins.helpers.
Когда ты делаешь...
from helpers import parse
... он находит helpers как пакет верхнего уровня, потому что он находится в вашем текущем рабочем каталоге.
Если вы хотите выполнить свой код из корня, мой лучший ответ на это — добавить в путь вашу корневую папку с помощью os.getcwd(). Убедитесь, что в вашей родственной папке есть файл в этом.py.
import os
os.sys.path.insert(0, os.getcwd())
from sibling import module
from . import foo?