问题: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来完成任务,而不是疲于应付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)
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/5542253和https://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.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”
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)