2009-08-13 1 views
135

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

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

thefile=open('test.csv') 

или:

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

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

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

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

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

ответ

184

Попробуйте использовать имя файла относительно текущего пути к файлам. Пример './my_file':

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

Я думаю, что это решение будет работать только если ресурс находится в том же каталоге файла питона, или в подкаталоге этого. Как вы решаете, когда вы имеете следующую древовидную структуру: /Project_Root_dir /python_files_dir /Некоторые другие подкаталоги здесь py_file.py /ресурсы /некоторые подкаталоги здесь resource_file.csv – olamundo

+0

К сожалению, файл дерево получило искаженные на этом последнем сообщении ... вторая попытка: у вас есть файл /Project_Root_dir/python_files_dir/some_subdirs/py_file.py, и у вас есть файл ресурсов в /Project_Root_dir/resources/some_subdirs/resource_file.csv – olamundo

+22

Вы должны быть в состоянии получить в родительский каталог, используя join (foo, '..'). Поэтому из/root/python_files/module/myfile используйте os.path.join (os.path.dirname ('__file__'), '..', '..', 'resources') – c089

1

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

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

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

+0

очень мало случаев использования, где 'cwd' - это путь к модулю, хотя – cedbeu

9

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

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.

-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 

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

+4

Это будет работать, только если вы используете программу Python из того же каталога, что и указанный .py-файл. И в этом случае вы могли бы просто «открыть» («ваша/подпапка/из/выбор») в любом случае. –

+3

и OP упомянул, что код должен работать как на Windows, так и на Linux. Это не будет. – user183037

26

Если вы используете инструменты установки или распространяете (установка 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

+3

Я знаю, что это старый ответ, мой предпочтительный способ (или может быть?) Использовать pkg_resources, но с исчезновением замятых яиц, есть ли вред только при использовании '' __file__'', как в старые добрые времена? – Pykler

+0

Это прочный подход. Даже если соглашение о яйцах уходит, setuptools нет, и многие из них все еще устанавливают deps против git repos, где яйцо построено во время выполнения – deepelement

3

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

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

import os 
package_dir = os.path.dirname(os.path.abspath(__file__)) 
thefile = os.path.join(package_dir,'test.cvs') 
Смежные вопросы