Python中的相对路径

问题:Python中的相对路径

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

I’m building a simple helper script for work that will copy a couple of template files in our code base to the current directory. I don’t, however, have the absolute path to the directory where the templates are stored. I do have a relative path from the script but when I call the script it treats that as a path relative to the current working directory. Is there a way to specify that this relative url is from the location of the script instead?


回答 0

在具有脚本的文件中,您想要执行以下操作:

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

这将为您提供要查找的文件的绝对路径。请注意,如果您使用的是setuptools,则应该改用其包资源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

但是,我确实知道__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计算机上引发了异常。

In the file that has the script, you want to do something like this:

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

This will give you the absolute path to the file you’re looking for. Note that if you’re using setuptools, you should probably use its package resources API instead.

UPDATE: I’m responding to a comment here so I can paste a code sample. :-)

Am I correct in thinking that __file__ is not always available (e.g. when you run the file directly rather than importing it)?

I’m assuming you mean the __main__ script when you mention running the file directly. If so, that doesn’t appear to be the case on my system (python 2.5.1 on 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

However, I do know that there are some quirks with __file__ on C extensions. For example, I can do this on my 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'

However, this raises an exception on my Windows machine.


回答 1

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

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

you need os.path.realpath (sample below adds the parent directory to your path)

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

回答 2

如已接受的答案中所述

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

在某些情况下,可接受的答案可能会误导您,请参阅链接以获取详细信息

As mentioned in the accepted answer

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

I just want to add that

the latter string can’t begin with the backslash , infact no string should include a backslash

It should be something like

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

The accepted answer can be misleading in some cases , please refer to this link for details


回答 3

现在是2018年,Python已经发展到__future__很久以前了。因此,如何使用神奇pathlib与Python 3.4来完成任务,而不是疲于应付osos.pathglobshutil,等。

因此,这里有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)

It’s 2018 now, and Python have already evolve to the __future__ long time ago. So how about using the amazing pathlib coming with Python 3.4 to accomplish the task instead of struggling with os, os.path, glob, shutil, etc.

So we have 3 paths here (possibly duplicated):

  • mod_path: which is the path of the simple helper script
  • src_path: which contains a couple of template files waiting to be copied.
  • cwd: current directory, the destination of those template files.

and the problem is: we don’t have the full path of src_path, only know it’s relative path to the mod_path.

Now let’s solve this with the the amazing 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()

In the future, it just that simple. :D


Moreover, we can select and check and copy/move those template files with 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)

回答 4

考虑我的代码:

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)

Consider my code:

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)

回答 5

请参见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'

See sys.path As initialized upon program startup, the first item of this list, path[0], is the directory containing the script that was used to invoke the Python interpreter.

Use this path as the root folder from which you 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'

回答 6

而不是使用

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

Instead of using

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

as in the accepted answer, it would be more robust to use:

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

because using __file__ will return the file from which the module was loaded, if it was loaded from a file, so if the file with the script is called from elsewhere, the directory returned will not be correct.

These answers give more detail: https://stackoverflow.com/a/31867043/5542253 and https://stackoverflow.com/a/50502/5542253


回答 7

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

总之os.path.abspath则(路径)使一个相对路径绝对路径。如果提供的路径本身是绝对路径,则该函数将返回相同的路径。

类似地 os.path.relpath(path)绝对路径设为相对路径。如果提供的路径本身是相对路径,则该函数将返回相同的路径。

下面的示例可以使您正确理解以上概念

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

D:\ conc \ input1.dic

D:\ conc \ input2.dic

D:\ Copyioconc \ input_file_list.txt

如果您看到上述文件夹结构,则copyofconc文件夹中存在input_file_list.txt,而python脚本中要处理的文件则存在于 conc文件夹文件

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

.. \ conc \ input1.dic

.. \ conc \ 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.dicinput2.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”

Hi first of all you should understand functions os.path.abspath(path) and os.path.relpath(path)

In short os.path.abspath(path) makes a relative path to absolute path. And if the path provided is itself a absolute path then the function returns the same path.

similarly os.path.relpath(path) makes a absolute path to relative path. And if the path provided is itself a relative path then the function returns the same path.

Below example can let you understand the above concept properly:

suppose i have a file input_file_list.txt which contains list of input files to be processed by my python script.

D:\conc\input1.dic

D:\conc\input2.dic

D:\Copyioconc\input_file_list.txt

If you see above folder structure, input_file_list.txt is present in Copyofconc folder and the files to be processed by the python script are present in conc folder

But the content of the file input_file_list.txt is as shown below:

..\conc\input1.dic

..\conc\input2.dic

And my python script is present in D: drive.

And the relative path provided in the input_file_list.txt file are relative to the path of input_file_list.txt file.

So when python script shall executed the current working directory (use os.getcwd() to get the path)

As my relative path is relative to input_file_list.txt, that is “D:\Copyofconc”, i have to change the current working directory to “D:\Copyofconc”.

So i have to use os.chdir(‘D:\Copyofconc’), so the current working directory shall be “D:\Copyofconc”.

Now to get the files input1.dic and input2.dic, i will read the lines “..\conc\input1.dic” then shall use the command

input1_path= os.path.abspath(‘..\conc\input1.dic’) (to change relative path to absolute path. Here as current working directory is “D:\Copyofconc”, the file “.\conc\input1.dic” shall be accessed relative to “D:\Copyofconc”)

so input1_path shall be “D:\conc\input1.dic”


回答 8

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

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

即使在模块中也可以使用。

This code will return the absolute path to the main script.

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

This will work even in a module.


回答 9

一个对我有用的替代方法:

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

An alternative which works for me:

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

回答 10

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

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

What worked for me is using sys.path.insert. Then I specified the directory I needed to go. For example I just needed to go up one directory.

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

回答 11

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

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

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

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

I’m not sure if this applies to some of the older versions, but I believe Python 3.3 has native relative path support.

For example the following code should create a text file in the same folder as the python script:

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

(note that there shouldn’t be a forward or backslash at the beginning if it’s a relative path)