Python中的相对路径

时间:2009-05-27 21:43:22

标签: python relative-path path

我正在构建一个简单的帮助脚本,用于将代码库中的几个模板文件复制到当前目录。但是,我没有存储模板的目录的绝对路径。我确实有一个来自脚本的相对路径,但是当我调用脚本时,它将其视为相对于当前工作目录的路径。有没有办法指定这个相对URL来自脚本的位置?

17 个答案:

答案 0 :(得分:246)

在包含脚本的文件中,您希望执行以下操作:

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

这将为您提供所需文件的绝对路径。请注意,如果您使用的是setuptools,则应该使用package resources API代替。

更新:我在这里回复评论,因此我可以粘贴代码示例。 : - )

  

我认为__file__并非始终可用(例如,当您直接运行文件而非导入文件时)时,我是否正确?

当您提到直接运行文件时,我假设您的意思是__main__脚本。如果是这样,我的系统上似乎不是这种情况(OS X 10.5.7上的python 2.5.1):

#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

但是,我确实知道在C扩展上存在__file__的一些怪癖。例如,我可以在我的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机器上引发异常。

答案 1 :(得分:57)

您需要os.path.realpath(以下示例将父目录添加到您的路径中)

import sys,os
sys.path.append(os.path.realpath('..'))

答案 2 :(得分:46)

如接受的答案中所述

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')

在某些情况下,接受的答案可能会产生误导,请参阅this链接了解详情

答案 3 :(得分:13)

考虑我的代码:

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)

答案 4 :(得分:10)

参见sys.path 在程序启动时初始化时,此列表的第一项path [0]是包含用于调用Python解释器的脚本的目录。

将此路径用作apply your relative path

的根文件夹
>>> 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'

答案 5 :(得分:9)

现在是2018年,Python很久以前就已经发展到__future__。那么,如何使用Python 3.4附带的出色pathlib来完成任务,而不是为osos.pathglobshutil等而苦苦挣扎。 / p>

所以我们这里有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)

答案 6 :(得分:5)

而不是使用

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/5542253https://stackoverflow.com/a/50502/5542253

答案 7 :(得分:4)

此代码将返回主脚本的绝对路径。

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

这甚至可以在模块中使用。

答案 8 :(得分:3)

首先,您应该了解函数 os.path.abspath(path) os.path.relpath(path)

简而言之, os.path.abspath(路径)会将相对路径设为绝对路径。如果提供的路径本身是绝对路径,则函数返回相同的路径。

同样 os.path.relpath(路径)绝对路径设为相对路径。如果提供的路径本身是一个相对路径,那么该函数返回相同的路径。

以下示例可让您正确理解上述概念

假设我有一个 input_file_list.txt 文件,其中包含我的python脚本要处理的输入文件列表。

d:\浓\ input1.dic

d:\浓\ input2.dic

d:\ Copyioconc \ input_file_list.txt

如果你看到上面的文件夹结构, copyofconc 文件夹中会出现 input_file_list.txt ,而python脚本要处理的文件会出现在 conc < / strong>文件夹

input_file_list.txt 文件的内容如下所示:

.. \浓\ input1.dic

.. \浓\ input2.dic

我的python脚本出现在 D:驱动器中。

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” ,应该相对于“D:\ Copyofconc”访问文件“。\ conc \ input1.dic”。

所以 input1_path 应为“D:\ conc \ input1.dic”

答案 9 :(得分:2)

另一种适合我的方法:

this_dir = os.path.dirname(__file__) 
filename = os.path.realpath("{0}/relative/file.path".format(this_dir))

答案 10 :(得分:2)

最重要的命令摘要

>>> import os
>>> os.path.join('/home/user/tmp', 'subfolder')
'/home/user/tmp/subfolder'
>>> os.path.normpath('/home/user/tmp/../test/..')
'/home/user'
>>> os.path.relpath('/home/user/tmp', '/home/user')
'tmp'
>>> os.path.isabs('/home/user/tmp')
True
>>> os.path.isabs('/tmp')
True
>>> os.path.isabs('tmp')
False
>>> os.path.isabs('./../tmp')
False
>>> os.path.realpath('/home/user/tmp/../test/..') # follows symbolic links
'/home/user'

docs中找到了详细说明。 这些是linux路径。 Windows应该可以类似地工作。

答案 11 :(得分:1)

对我有用的是使用sys.path.insert。然后我指定了我需要去的目录。例如,我只需要上一个目录。

import sys
sys.path.insert(0, '../')

答案 12 :(得分:0)

我认为要在所有系统上使用“ ntpath”而不是“ os.path”。今天,它可以在Windows,Linux和Mac OSX上很好地工作。

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

答案 13 :(得分:0)

根据其他建议和pathlib文档,以下是一种简单明了的解决方案(假设我们需要引用该文件:Test/data/users.csv

# This file location: Tests/src/long/module/subdir/some_script.py
from pathlib import Path

# back to Tests/
PROJECT_ROOT = Path(__file__).parents[4]
# then down to Test/data/users.csv
CSV_USERS_PATH = PROJECT_ROOT / 'data' / 'users.csv'  

with CSV_USERS_PATH.open() as users:
    print(users.read())

现在这对我来说有点奇怪,因为如果您四处移动some_script.py,到项目根目录的路径可能会更改(我们需要修改parents[4])。另一方面,我基于相同的想法找到了我更喜欢的解决方案。

假设我们具有以下目录结构:

Tests
├── data
│  └── users.csv
└── src
   ├── long
   │  └── module
   │     └── subdir
   │        └── some_script.py
   ├── main.py
   └── paths.py

paths.py文件将负责存储我们的projet的根目录:

from pathlib import Path

PROJECT_ROOT = Path(__file__).parents[1]

所有脚本现在都可以使用paths.PROJECT_ROOT来表示从项目根目录开始的绝对路径。例如,在src/long/module/subdir/some_script.py中,我们可以拥有:

from paths import PROJECT_ROOT

CSV_USERS_PATH = PROJECT_ROOT / 'data' / 'users.csv'

def hello():
    with CSV_USERS_PATH.open() as f:
        print(f.read())

一切都按预期进行:

~/Tests/src/$ python main.py

/Users/cglacet/Tests/data/users.csv
hello, user

~/Tests/$ python src/main.py

/Users/cglacet/Tests/data/users.csv
hello, user

main.py脚本就是:

from long.module.subdir import some_script

some_script.hello()

答案 14 :(得分:0)

一个简单的解决方案是

import os
os.chdir(os.path.dirname(__file__))

答案 15 :(得分:0)

C:\Users\xyz\myFolderC:\Users\xyz\testdata

import os
working_dir = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
# C:\Users\xyz\myFolder
print(working_dir)
updated_working_dir = os.path.join(os.path.realpath(working_dir + '/../'), 'testdata')
# C:\Users\xyz\testdata
print(updated_working_dir)
<块引用>

输出

C:\Users\xyz\myFolder
C:\Users\xyz\testdata

答案 16 :(得分:-2)

我不确定这是否适用于某些旧版本,但我相信Python 3.3具有本机相对路径支持。

例如,以下代码应在与python脚本相同的文件夹中创建一个文本文件:

open("text_file_name.txt", "w+t")

(请注意,如果它是相对路径,那么开头不应该有正斜杠或反斜杠)