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

160

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

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

thefile=open('test.csv')

или же:

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

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

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

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

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

Ваш Ответ

7   ответов
217

Пример для './мой файл':

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

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

fn = pathlib.Path(__file__).parent / 'my_file'
@ c089 спасибо, это действительно хороший момент cedbeu
Я думаю, что это решение будет работать, только если ресурс находится в том же каталоге файла Python или в его подкаталоге. Как вы решаете это, когда у вас есть следующая древовидная структура: / Project_Root_dir / python_files_dir / Еще несколько подкаталогов здесь py_file.py / resources / Некоторые подкаталоги здесь resource_file.csv olamundo
Извините, дерево файлов искажено в этом последнем сообщении ... вторая попытка: у вас есть файл по адресу /Project_Root_dir/python_files_dir/some_subdirs/py_file.py, а файл ресурсов по адресу /Project_Root_dir/resources/some_subdirs/resource_file.csv olamundo
Будет ли это работать в общей папке? Например, если у меня есть файлы и данные на моем компьютере в общей папке, а затем мой коллега в сети запускает файл .py, мне нужен код для ссылки на правильные файлы. trench
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__

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

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

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

11

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

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

import os
package_dir = os.path.dirname(os.path.abspath(__file__))
thefile = os.path.join(package_dir,'test.cvs')
-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') тем не мение. Paul Fisher
и ОП упоминал, что код должен работать как в Windows, так и в Linux. Этого не будет. user183037
32

ка setup.py), то "право" Кажется, что для доступа к этим упакованным ресурсам используется 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__ как старые добрые времена? Pykler
Это солидный подход. Даже если соглашение о яйцах уходит, setuptools неt и многие все еще устанавливают deps против git-репозиториев, где яйцо создается во время выполнения deepelement
7
import os
cwd = os.getcwd()
path = os.path.join(cwd, "my_file")
f = open(path)

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

это неработать внутри пакета, только из того же каталога (или рабочего каталога), который установлен сценарием. alexandra
очень мало случаев, когдаcwd это путь модуля, хотя cedbeu
2

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

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