Вопрос по project, python, repository, path, relative – Как ссылаться на относительные пути ресурсов при работе с хранилищем кода в Python

160

Мы работаем с хранилищем кода, которое развернуто как в Windows, так и в Linux - иногда в разных каталогах. Как один из модулей внутри проекта должен ссылаться на один из не-Python-ресурсов в проекте (файлы CSV и т. Д.)?

Если мы сделаем что-то вроде:

thefile=open('test.csv')

или же:

thefile=open('../somedirectory/test.csv')

Он будет работать только тогда, когда скрипт запускается из одного определенного каталога или подмножества каталогов.

То, что я хотел бы сделать, это что-то вроде:

path=getBasePathOfProject()+'/somedirectory/test.csv'
thefile=open(path)

Это правильный путь? Является ли это возможным?

Ваш Ответ

7   ответов
12

Я часто использую что-то похожее на это:

import os
DATA_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), 'datadir'))

# if you have more paths to set, you might want to shorten this as
here = lambda x: os.path.abspath(os.path.join(os.path.dirname(__file__), x))
DATA_DIR = here('datadir') 

pathjoin = os.path.join
# ...
# later in script
for fn in os.listdir(DATA_DIR):
    f = open(pathjoin(DATA_DIR, fn))
    # ...

Переменная

__file__

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

path is absolute, but still relative the project can still be deployed in a relative container

Но вам нужно следить за совместимостью платформы - Windows & apos; os.pathsep отличается от UNIX.

217

Попробуйте использовать имя файла относительно текущего пути к файлам. Пример для & apos; ./ my_file & amp;

fn = os.path.join(os.path.dirname(__file__), 'my_file')

В Python 3.4+ вы также можете использоватьpathlib:

fn = pathlib.Path(__file__).parent / 'my_file'
os.pardir немного лучше чем'..'хотя эти два варианта эквивалентны как для POSIX, так и для Windows.
Извините, дерево файлов искажено в этом последнем сообщении ... вторая попытка: у вас есть файл по адресу /Project_Root_dir/python_files_dir/some_subdirs/py_file.py и у вас есть файл ресурсов по адресу /Project_Root_dir/resources/some_subdirs/resource_file.csv olamundo
Вы должны иметь возможность получить доступ к родительскому каталогу, используя join (foo, & apos; .. & apos;). Поэтому из / root / python_files / module / myfile используйте os.path.join (os.path.dirname (__file__), «...», «...», «ресурсы»)
Я думаю, что это решение будет работать, только если ресурс находится в том же каталоге файла Python или в его подкаталоге. Как вы решаете это, когда у вас есть следующая древовидная структура: / Project_Root_dir / python_files_dir / Еще несколько подкаталогов здесь py_file.py / resources / Некоторые подкаталоги здесь resource_file.csv olamundo
@cedbeu: Это эквивалентно на каждой системе, с которой я когда-либо сталкивался, и я думаю, что каждый системный питон работает сегодня (пожалуйста, исправьте меня, если я ошибаюсь здесь). Однако, если вы ожидаете, что Python будет перенесен в систему с использованием другого разделителя пути в будущем, и хотите, чтобы ваш код был готов к этому, os.pardir будет более переносимым. Я бы сказал, что каждый программист, даже тот, кто никогда не читает ни одного Python, знает значение слова "...", а "os.pardir". это уровень косвенности, который нужно было бы найти в документации, так что лично я "придерживаюсь" .. ".
-1

Я потратил много времени на то, чтобы найти ответ на этот вопрос, но, наконец, я его получил (и это действительно очень просто):

import sys
import os
sys.path.append(os.getcwd() + '/your/subfolder/of/choice')

# now import whatever other modules you want, both the standard ones,
# as the ones supplied in your subfolders

Это добавит относительный путь вашей подпапки в каталоги для поиска в Python Это довольно быстро и грязно, но работает как шарм :)

Это будет работать только в том случае, если вы запускаете программу Python из того же каталога, что и рассматриваемый файл .py. И в этом случае вы могли бы просто сделатьopen('your/subfolder/of/choice') тем не мение.
и ОП упомянул, что код должен работать как в Windows, так и в Linux. Этого не будет.
32

Если вы используете инструменты установки или распространяете (установка setup.py), то & quot; право & quot; Кажется, что для доступа к этим упакованным ресурсам используется package_resources.

В вашем случае пример будет

import pkg_resources
my_data = pkg_resources.resource_string(__name__, "foo.dat")

Который, конечно, читает ресурс, и считанные двоичные данные будут значением my_data

Если вам просто нужно имя файла, вы также можете использовать

resource_filename(package_or_requirement, resource_name)

Пример:

resource_filename("MyPackage","foo.dat")

Преимущество заключается в том, что он гарантированно работает, даже если это архивное распределение, как яйцо

Увидетьhttp://packages.python.org/distribute/pkg_resources.html#resourcemanager-api

Я знаю, что это старый ответ, мой предпочтительный способ (/ было возможно?) Использовать pkg_resources, но с исчезновением яиц с молнией, есть ли вред при использовании__file__ как старые добрые времена?
Это солидный подход. Даже если соглашение с яйцами прекращается, setuptools не работает, и многие все еще устанавливают deps против git-репозиториев, где яйцо создается во время выполнения.
11

В Python пути относительноcurrent working directory, который в большинстве случаев является каталогом, из которого вы запускаете вашу программу.current working directory Скорее всего, это не то же самое, что каталог вашего файла модуля, поэтому использование пути относительно вашего текущего файла модуля всегда является плохим выбором.

Использование абсолютного пути должно быть лучшим решением:

import os
package_dir = os.path.dirname(os.path.abspath(__file__))
thefile = os.path.join(package_dir,'test.cvs')
2

Вы можете использовать сборку в__file__ переменная. Содержит путь к текущему файлу. Я бы реализовал getBaseOfProject в модуле в корне вашего проекта. Там я бы получил часть пути__file__ и вернул бы это. Этот метод может быть использован везде в вашем проекте.

7
import os
cwd = os.getcwd()
path = os.path.join(cwd, "my_file")
f = open(path)

Вы также пытаетесь нормализоватьcwd с помощьюos.path.abspath(os.getcwd()), Больше информацииВот.

очень мало случаев, когдаcwd это путь модуля, хотя

Похожие вопросы