организация питонного модуля - как обращаться к файлам в корневом каталоге? - PullRequest
6 голосов
/ 06 декабря 2011

У меня есть код Python в папке с именем "project", поэтому мои файлы кода находятся в проекте / *. Py.Я хочу иметь подмодули внутри него, например,

project/code.py # where code lives
project/mymodule1  # where more code lives
project/mymodule2

каждый каталог модуля имеет свой собственный файл init .py, например,

project/mymodule1/__init__.py

предположим, у меня есть файл«test.py» в mymodule1 (project / mymodule1 / test.py), и я хотел бы сослаться на что-то из «code», например, импортировать функцию «myfunc»

== project/mymodule1/test.py ==
from code import myfunc

, проблема в том, что«Код» не будет найден, если пользователь не поместит каталог «project /» в свою PYTHONPATH.Есть ли способ избежать этого и использовать какой-то «относительный путь» для импорта myfunc, например,

from ../code import myfunc

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

Как это можно сделать?Любое решение является хорошим: изменение PYTHONPATH программно или, что более важно, обращение к «коду» с использованием некоторого относительного импорта, поскольку, хотя я не знаю, где «project / code.py» живет на компьютере пользователя, я знаю, гдеэто относительно "myfunc".

РЕДАКТИРОВАТЬ: Может кто-нибудь показать правильный пример импорта внутри пакета?Я попытался из "mymodule1" сделать:

from .. import foo

, где "foo" находится в code.py, но он не работает.У меня есть init .py в mymodule1, поэтому:

project/code.py
project/mymodule1/__init__.py
project/mymodule1/module1_code.py

, где module1_code.py пытается импортировать foo, функцию, определенную в "code.py".

РЕДАКТИРОВАТЬ: Основная путаница у меня все еще есть, что даже после принятия примера, приведенного в ответ на мое сообщение, показывая иерархию проекта / sub1 / test, вы все равно не можете "cd" в sub1 и сделать "python test.py" и иметь егоРабота.Пользователь должен находиться в каталоге, содержащем «project», и выполнить «import project.sub1.test».Я бы хотел, чтобы это работало независимо от того, в каком каталоге находится пользователь. В этом случае пользователь должен выполнить файл "test.py", который находится в проекте / sub1 /.Итак, контрольный пример:

$ cd project/sub1
$ python test.py

, что приводит к ошибке:

ValueError: Attempted relative import in non-package

как это можно исправить?

спасибо.

Ответы [ 2 ]

3 голосов
/ 06 декабря 2011

Это возможно в Python 2.5 и выше.См. Документы Ссылки внутри пакета .

Несколько замечаний:

Если вы хотите, чтобы ваши пользователи установили ваш пакетгде-нибудь, например, используя distutils или setuptools, тогда project, вероятно, уже будет в пути поиска, и вы можете изменить относительный импорт на from project.code import ... или аналогичный.

В случае, когда ваши пользователи устанавливаютВаш пакет находится в нестандартном каталоге (например, в его домашнем каталоге, где-то еще, которого нет в sys.path и т. д.), мое мнение таково, что это приводит к меньшей путанице в том, что пользователь может изменить PYTHONPATH, а не программно изменять sys.path.

В том случае, если вы вообще не собираетесь устанавливать свой код для своих пользователей - например, они просто извлекут исходный код, перейдя в родительский каталог project,и запуск скрипта - тогда внутрипакетные ссылки и относительный импорт, вероятно, будут работать нормально.

EDIT : для запроса, вот пример:

SupposСтруктура пакета выглядит следующим образом:

project/
    __init__.py (empty)
    code.py
    sub1/
        __init__.py (empty)
        test.py

Теперь содержимое project/code.py:

# code.py (module that resides in main "project" package)

def foo():
    print "this is code.foo"

И содержимое project/sub1/test.py:

# test.py (module that resides in "sub1" subpackage of main "project" package)

from ..code import foo
foo()

Итак, test.py импортирует имя foo из относительного пути ..code, который использует внутрипакетные ссылки, чтобы вернуть нас к модулю code.py внутри parent (это.. часть) пакета sub1.test, из которого мы выполняем.

Чтобы проверить это:

shell$ (cd to directory where "project" package is located)
shell$ python
Python 2.6.1 (r261:67515, Aug  2 2010, 20:10:18) 
[GCC 4.2.1 (Apple Inc. build 5646)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import project.sub1.test
this is code.foo

Обратите внимание, что двойная точка в синтаксисе from .. import X просто получаетвы к родительскому пакету, но вы можете указать модули в этом пакете.

Другими словами, from .. import X в этом случае эквивалентно from project import X, поэтому X должен быть либо модулем в project, либо классом / функцией / именем в project/__init__.py.

Таким образом, from ..code import X эквивалентно from project.code import X.

1 голос
/ 06 декабря 2011

лучший способ избежать этого - хранить весь свой код в папке src или лучше назвать его в своем проекте, например. myproject и оставьте __init__.py там, чтобы вы могли сделать это

from myproject import code

так что ваша структура папок будет

project
    main.py
    myproject
        __init__.py
        code.py
        module1
        module2

main.py или любое другое имя, которое вы даете, не должно содержать много кода, оно должно получить требуемый модуль из myproject и запустить его, например,

from myproject import myapp
myapp.run()

см. Хорошую статью о том, как организовать ваш проект на Python.

...