Python中的相对路径
我正在为工作写一个简单的辅助脚本,这个脚本会把我们代码库中的几个模板文件复制到当前的目录里。不过,我并不知道模板文件存放的绝对路径。虽然我有一个相对路径,但当我运行这个脚本时,它会把这个路径当作是相对于当前工作目录的路径。有没有办法让这个相对路径是从脚本所在的位置开始的呢?
21 个回答
76
你需要用到 os.path.realpath
这个功能(下面的例子是把父目录添加到你的路径中)
import sys,os
sys.path.append(os.path.realpath('..'))
116
现在是2018年,Python早就发展到了__future__
这个阶段。所以我们可以用Python 3.4自带的超棒的pathlib
来完成这个任务,而不是费力地去用os
、os.path
、glob
、shutil
等等。
这里我们有三个路径(可能有重复的):
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()
将来,这样做就是这么简单。
而且,我们可以用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)
546
在包含脚本的文件中,你想要做的事情大概是这样的:
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机器上这样做会引发一个异常。