Относительные пути в Python - PullRequest
184 голосов
/ 28 мая 2009

Я создаю простой вспомогательный скрипт для работы, который скопирует пару файлов шаблонов из нашей базы кода в текущий каталог. Однако у меня нет абсолютного пути к каталогу, в котором хранятся шаблоны. У меня есть относительный путь из сценария, но когда я вызываю сценарий, он обрабатывает его как путь относительно текущего рабочего каталога. Есть ли способ указать, что этот относительный URL-адрес находится вместо расположения сценария?

Ответы [ 12 ]

248 голосов
/ 28 мая 2009

В файле, в котором есть скрипт, вы хотите сделать что-то вроде этого:

import os
dirname = os.path.dirname(__file__)
filename = os.path.join(dirname, 'relative/path/to/file/you/want')

Это даст вам абсолютный путь к файлу, который вы ищете. Обратите внимание, что если вы используете setuptools, вам, вероятно, следует использовать вместо него API ресурсов пакета .

ОБНОВЛЕНИЕ : Я отвечаю на комментарий, чтобы вставить образец кода. : -)

Правильно ли я считаю, что __file__ не всегда доступен (например, когда вы запускаете файл напрямую, а не импортируете его)?

Я предполагаю, что вы имеете в виду сценарий __main__, когда упоминаете прямой запуск файла. Если так, то в моей системе это не так (python 2.5.1 в OS X 10.5.7):

#foo.py
import os
print os.getcwd()
print __file__

#in the interactive interpreter
>>> import foo
/Users/jason
foo.py

#and finally, at the shell:
~ % python foo.py
/Users/jason
foo.py

Однако я знаю, что есть некоторые причуды с __file__ на расширениях C. Например, я могу сделать это на моем Mac:

>>> import collections #note that collections is a C extension in Python 2.5
>>> collections.__file__
'/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/lib-
dynload/collections.so'

Однако на моем компьютере с Windows возникает исключение.

58 голосов
/ 19 марта 2012

вам нужно os.path.realpath (пример ниже добавляет родительский каталог к ​​вашему пути)

import sys,os
sys.path.append(os.path.realpath('..'))
46 голосов
/ 28 апреля 2016

Как указано в принятом ответе

import os
dir = os.path.dirname(__file__)
filename = os.path.join(dir, '/relative/path/to/file/you/want')

Я просто хочу добавить это

последняя строка не может начинаться с обратной косой черты, фактически нет строки должен включать обратную косую черту

Это должно быть что-то вроде

import os
dir = os.path.dirname(__file__)
filename = os.path.join(dir, 'relative','path','to','file','you','want')

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

13 голосов
/ 06 октября 2015

Рассмотрим мой код:

import os


def readFile(filename):
    filehandle = open(filename)
    print filehandle.read()
    filehandle.close()



fileDir = os.path.dirname(os.path.realpath('__file__'))
print fileDir

#For accessing the file in the same folder
filename = "same.txt"
readFile(filename)

#For accessing the file in a folder contained in the current folder
filename = os.path.join(fileDir, 'Folder1.1/same.txt')
readFile(filename)

#For accessing the file in the parent folder of the current folder
filename = os.path.join(fileDir, '../same.txt')
readFile(filename)

#For accessing the file inside a sibling folder.
filename = os.path.join(fileDir, '../Folder2/same.txt')
filename = os.path.abspath(os.path.realpath(filename))
print filename
readFile(filename)
10 голосов
/ 28 мая 2009

См. sys.path Как инициализируется при запуске программы, первый элемент этого списка, path [0], является каталогом, содержащим скрипт, который использовался для вызова интерпретатора Python.

Используйте этот путь в качестве корневой папки, из которой вы применяете свой относительный путь

>>> import sys
>>> import os.path
>>> sys.path[0]
'C:\\Python25\\Lib\\idlelib'
>>> os.path.relpath(sys.path[0], "path_to_libs") # if you have python 2.6
>>> os.path.join(sys.path[0], "path_to_libs")
'C:\\Python25\\Lib\\idlelib\\path_to_libs'
9 голосов
/ 03 июля 2018

Сейчас 2018 год, и Python уже давно превратился в __future__. Так как насчет использования удивительных pathlib, поставляемых с Python 3.4, для выполнения задачи вместо того, чтобы бороться с os, os.path, glob, shutil и т. Д.

Итак, у нас есть 3 пути (возможно, дублированные):

  • mod_path: путь к простому вспомогательному сценарию
  • src_path: содержит пару файлов шаблонов , ожидающих копирования.
  • cwd: текущий каталог , место назначения этих файлов шаблонов.

и проблема в том, что у нас нет полного пути src_path, мы знаем только это относительный путь к mod_path.

Теперь давайте решим это с помощью удивительного pathlib:

# Hope you don't be imprisoned by legacy Python code :)
from pathlib import Path

# `cwd`: current directory is straightforward
cwd = Path.cwd()

# `mod_path`: According to the accepted answer and combine with future power
# if we are in the `helper_script.py`
mod_path = Path(__file__).parent
# OR if we are `import helper_script`
mod_path = Path(helper_script.__file__).parent

# `src_path`: with the future power, it's just so straightforward
relative_path_1 = 'same/parent/with/helper/script/'
relative_path_2 = '../../or/any/level/up/'
src_path_1 = (mod_path / relative_path_1).resolve()
src_path_2 = (mod_path / relative_path_2).resolve()

В будущем это так просто. : D


Более того, мы можем выбирать, проверять и копировать / перемещать эти файлы шаблонов с помощью pathlib:

if src_path != cwd:
    # When we have different types of files in the `src_path`
    for template_path in src_path.glob('*.ini'):
        fname = template_path.name
        target = cwd / fname
        if not target.exists():
            # This is the COPY action
            with target.open(mode='wb') as fd:
                fd.write(template_path.read_bytes())
            # If we want MOVE action, we could use:
            # template_path.replace(target)
5 голосов
/ 19 февраля 2016

Вместо использования

import os
dirname = os.path.dirname(__file__)
filename = os.path.join(dirname, 'relative/path/to/file/you/want')

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

import inspect
import os
dirname = os.path.dirname(os.path.abspath(inspect.stack()[0][1]))
filename = os.path.join(dirname, 'relative/path/to/file/you/want')

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

Эти ответы дают более подробную информацию: https://stackoverflow.com/a/31867043/5542253 и https://stackoverflow.com/a/50502/5542253

4 голосов
/ 24 марта 2016

Этот код вернет абсолютный путь к основному сценарию.

import os
def whereAmI():
    return os.path.dirname(os.path.realpath(__import__("__main__").__file__))

Это будет работать даже в модуле.

3 голосов
/ 07 декабря 2013

Привет, прежде всего, вы должны понимать функции os.path.abspath (путь) и os.path.relpath (путь)

Короче говоря os.path.abspath (путь) создает относительный путь до абсолютный путь . И если указанный путь сам по себе является абсолютным, то функция возвращает тот же путь.

аналогично os.path.relpath (путь) создает абсолютный путь до относительный путь . И если указанный путь является относительным, то функция возвращает тот же путь.

Приведенный ниже пример поможет вам правильно понять вышеуказанную концепцию :

предположим, у меня есть файл input_file_list.txt , который содержит список входных файлов, которые будут обработаны моим скриптом python.

D: \ конц \ input1.dic

D: \ конц \ input2.dic

D: \ Copyioconc \ input_file_list.txt

Если вы видите вышеупомянутую структуру папок, input_file_list.txt присутствует в папке Copyofconc , а файлы для обработки скриптом python присутствуют в conc папка

Но содержимое файла input_file_list.txt показано ниже:

.. \ конц \ input1.dic

.. \ конц \ input2.dic

А мой скрипт на python присутствует в D: drive.

И относительный путь, указанный в файле input_file_list.txt , относительно пути к файлу input_file_list.txt .

Поэтому, когда скрипт Python должен выполнить текущий рабочий каталог (используйте os.getcwd () , чтобы получить путь)

Поскольку мой относительный путь относительно input_file_list.txt , то есть "D: ​​\ Copyofconc" , мне нужно изменить текущий рабочий каталог на "D: \ Copyofconc ".

Так что мне нужно использовать os.chdir ('D: \ Copyofconc') , поэтому текущий рабочий каталог должен быть "D: ​​\ Copyofconc" .

Теперь, чтобы получить файлы input1.dic и input2.dic , я прочитаю строки ".. \ conc \ input1.dic", затем воспользуюсь командой

input1_path = os.path.abspath ('.. \ conc \ input1.dic') (чтобы изменить относительный путь на абсолютный путь. Здесь текущим рабочим каталогом является "D: \ Copyofconc", файл ". \ conc \ input1.dic" должен быть доступен относительно "D: \ Copyofconc")

, поэтому input1_path должно быть "D: \ conc \ input1.dic"

2 голосов
/ 10 октября 2014

Альтернатива, которая работает для меня:

this_dir = os.path.dirname(__file__) 
filename = os.path.realpath("{0}/relative/file.path".format(this_dir))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...