我正在构建一个简单的助手脚本,用于将代码库中的两个模板文件复制到当前目录。但是,我没有存储模板的目录的绝对路径。我有一个相对路径从脚本,但当我调用脚本,它把它作为一个相对于当前工作目录的路径。是否有一种方法来指定这个相对url是来自脚本的位置?


当前回答

在有脚本的文件中,你想做这样的事情:

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

然而,我确实知道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机器上引发一个异常。

其他回答

根据其他建议和pathlib文档,一个简单(但不理想)的解决方案如下(假设我们需要引用的文件是Test/data/users.csv):

# Current 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,到项目根目录的路径可能会改变(因此我们需要更改父目录[4]部分)。

我想我找到了一个更好的解决方案,基于同样的想法。 我们将使用path .py文件来存储项目的根目录,与根目录相比,这个文件将保持在相同的位置。

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

path .py的唯一职责是提供PROJECT_ROOT:

from pathlib import Path

PROJECT_ROOT = Path(__file__).parents[1]

所有脚本现在都可以使用路径。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()

Hi首先你需要理解os。path。abspath(path)和os。path。relpath(path)

简而言之,os.path.abspath(path)将相对路径转换为绝对路径。如果提供的路径本身是一个绝对路径,那么函数返回相同的路径。

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

下面的例子可以让你正确理解上面的概念:

假设我有一个文件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”这行。然后使用命令

Input1_path = os.path.abspath('..\conc\input1.dic')(将相对路径更改为绝对路径。这里作为当前的工作目录是“D:\Copyofconc”,文件“.\conc\input1.”相对于"D:\Copyofconc")

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

这是向系统路径集添加相对路径的简单方法。例如,对于目标目录比工作目录高一级(例如'/../')的常见情况:

import os
import sys
workingDir = os.getcwd()
targetDir = os.path.join(os.path.relpath(workingDir + '/../'),'target_directory')
sys.path.insert(0,targetDir)

对该解决方案进行了测试:

Python 3.9.6 |由conda-forge |打包(默认,2021年7月11日, 03:37:25) [MSC .1916 64位(AMD64)]

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

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

假设当前的存档文件名为“Helper”,上面的目录名为“Workshop”,模板文件在\Workshop\Templates中,那么Python中的相对路径为“..\Templates”。