Python - не удается импортировать пакет

У меня проблемы с импортом package. Моя файловая структура выглядит следующим образом:

filelib/  
    __init__.py
    converters/ 
        __init__.py
        cmp2locus.py
    modelmaker/ 
        __init__.py
        command_file.py

В модуле command_file.py у меня есть класс с именем CommandFile, который я хочу вызвать в модуле cmp2locus.py.

Я пробовал следующее в модуле cmp2locus.py:

import filelib.modelmaker.command_file
import modelmaker.command_file
from filelib.modelmaker.command_file import CommandFile

Все эти параметры возвращают ImportError: No modules named ... Цените любой намек на решение этой проблемы. Я не понимаю, почему этот импорт не работает.


person duanerf    schedule 17.03.2017    source источник
comment
Возможный дубликат Постоянное добавление папки в путь Python   -  person moe assal    schedule 22.09.2019


Ответы (2)


Чтобы выполнить этот импорт, у вас есть 3 варианта, я перечислю их в том порядке, в котором я предпочитаю. (Для всех этих вариантов я буду использовать Python 3)

Относительный импорт

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

Вам также потребуется запустить скрипт, выполняющий импорт из-за пределов пакета, например, импортировав его и запустив оттуда, а не просто запустив скрипт cmp2locus.py напрямую.

Затем вам нужно будет изменить импорт, чтобы он был относительным, используя .. Итак:

import filelib.modelmaker.command_file

становится

from ..modelmaker import command_file

.. относится к родительской папке (например, к скрытому файлу в файловых системах). Также обратите внимание, что вы должны использовать синтаксис from import, потому что имена, начинающиеся с .., не являются допустимыми идентификаторами в python. Однако вы, конечно, можете импортировать его как угодно, используя from import as.

См. также PEP.

Абсолютный импорт

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

Изменение пути Python

Как ответил Meera, вы также можете напрямую изменить путь python, используя sys.

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

person Blimmo    schedule 17.03.2017
comment
Спасибо @Блиммо. Мне нравится идея относительного импорта. На самом деле я использую Python2.7. Если я попробую ваш suggestion:from ..modelmaker import command_file, я получу следующую ошибку: ValueError: Attempted relative import in non-package. Нужно ли мне что-то особенное в моем initi.py, чтобы это работало? Или это Python2.7 предотвращает это? - person duanerf; 17.03.2017
comment
Я только что понял комментарий, а не просто запустил cmp2locus.py. Я не уверен, что понимаю, откуда я должен импортировать его, если я хочу использовать его в этом конкретном модуле. - person duanerf; 17.03.2017
comment
@duanerf Вам просто нужно вызвать скрипт, который вы хотите импортировать из другого места изначально, скрипт все еще может использовать импорт в нем. Это связано с тем, что пакеты Python на самом деле не должны запускаться сами по себе, а просто использоваться. Таким образом, вы можете сделать run.py вне пакета, состоящего только из import filelib.converters.cmp2locus. Это запустит скрипт извне, что позволит загрузить пакет. Это может оказаться полезным. - person Blimmo; 17.03.2017

Чтобы импортировать из другой папки, вы должны добавить этот путь к папке в sys.path:

import sys
sys.path.append('path/filelib/modelmaker')
import command_file
person Meera    schedule 17.03.2017
comment
Спасибо @Мира. Однако кажется, что это не добавляет путь навсегда. Это означает, что мне нужно всегда добавлять этот sys.path.append в мой код. Я нахожу это странным и никогда не замечал, что это необходимо. Есть ли способ навсегда добавить мой пакет filelib в sys.path, чтобы затем импортировать все, что есть в этой библиотеке? - person duanerf; 17.03.2017