[英]Relative paths in Python
我正在为工作构建一个简单的帮助脚本,它将我们代码库中的几个模板文件复制到当前目录。 但是,我没有存储模板的目录的绝对路径。 我确实有来自脚本的相对路径,但是当我调用脚本时,它会将其视为相对于当前工作目录的路径。 有没有办法指定这个相对 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 机器上引发异常。
您需要os.path.realpath
(下面的示例将父目录添加到您的路径中)
import sys,os
sys.path.append(os.path.realpath('..'))
如已接受的答案中所述
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')
在某些情况下,接受的答案可能会产生误导,请参阅此链接了解详细信息
现在是 2018 年,Python 早就进化到了__future__
。 那么如何使用 Python 3.4 pathlib
的惊人的pathlib
来完成任务,而不是在os
、 os.path
、 glob
、 shutil
等中挣扎。
所以我们这里有 3 条路径(可能是重复的):
mod_path
: 这是简单帮助脚本的路径src_path
:其中包含几个等待复制的模板文件。cwd
:当前目录,这些模板文件的目的地。 而问题是:我们没有的完整路径src_path
,只知道它的的相对路径mod_path
。
# 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)
考虑我的代码:
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)
请参见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'
而不是使用
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
嗨,首先你应该了解函数os.path.abspath(path)和os.path.relpath(path)
简而言之os.path.abspath(path)使相对路径到绝对路径。 如果提供的路径本身是绝对路径,则该函数返回相同的路径。
类似地, os.path.relpath(path)是相对路径的绝对路径。 如果提供的路径本身是一个相对路径,则该函数返回相同的路径。
下面的例子可以让你正确理解上述概念:
假设我有一个文件input_file_list.txt ,其中包含要由我的 python 脚本处理的输入文件列表。
D:\\conc\\input1.dic
D:\\conc\\input2.dic
D:\\Copyioconc\\input_file_list.txt
如果你看到上面的文件夹结构, input_file_list.txt存在于Copyofconc文件夹中,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.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”
此代码将返回主脚本的绝对路径。
import os
def whereAmI():
return os.path.dirname(os.path.realpath(__import__("__main__").__file__))
这甚至可以在模块中工作。
对我有用的替代方法:
this_dir = os.path.dirname(__file__)
filename = os.path.realpath("{0}/relative/file.path".format(this_dir))
>>> 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'
文档中有详细说明。 这些是linux路径。 Windows 应该以类似的方式工作。
从其他人的建议和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
文件将负责存储我们项目的根位置:
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()
对我sys.path.insert
是使用sys.path.insert
。 然后我指定了我需要去的目录。 例如,我只需要上一个目录。
import sys
sys.path.insert(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')
一个简单的解决方案是
import os
os.chdir(os.path.dirname(__file__))
从C:\\Users\\xyz\\myFolder
到C:\\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
示例,在 python 3.9.5 中测试
您当前的目录:'c:\\project1\\code'
并且您想要访问以下文件夹:“c:\\project1\\dataset\\train”。
然后您可以使用以下地址访问该文件夹:'../dataset/train/'
我认为这可能对某人有用!
这是我的总结:
首先,定义名为relpath
的工具函数,它将当前文件的相对路径转换为 cwd 的相对路径
import os
relpath = lambda p: os.path.normpath(os.path.join(os.path.dirname(__file__), p))
然后我们用它来包装相对于当前文件的路径
path1 = relpath('../src/main.py')
你也可以调用sys.path.append()
来导入相对于当前文件位置的文件
sys.path.append(relpath('..')) # so that you can import from upper dir
完整示例代码: https : //gist.github.com/luochen1990/9b1ffa30f5c4a721dab5991e040e3eb1
假设当前存档名为“Helper”,上层目录名为“Workshop”,模板文件在\\Workshop\\Templates,那么Python中的相对路径为“..\\Templates”。
这是一种将相对路径添加到系统路径集的简单方法。 例如,对于目标目录比工作目录高一级(因此, '/../'
)的常见情况:
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 v.1916 64 位 (AMD64)]
我不确定这是否适用于某些旧版本,但我相信 Python 3.3 具有本机相对路径支持。
例如,以下代码应在与 python 脚本相同的文件夹中创建一个文本文件:
open("text_file_name.txt", "w+t")
(请注意,如果是相对路径,则开头不应有正斜杠或反斜杠)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.