获取Python中调用者的相对路径

时间:2015-01-19 09:32:36

标签: python path

我有这个功能:

def relative_path(*paths):
    return os.path.join(os.path.dirname(__file__), *paths)

我如何更改它以返回相对于来电者的路径

例如,如果我从另一个脚本调用relative_path('index.html'),是否可以从隐式调用它的位置获取相对于脚本的路径,或者我是否需要修改relative_path以传递{{1}像这样??

__file__

2 个答案:

答案 0 :(得分:2)

Get __name__ of calling function's module in Python

中调整解决方案

file1.py

import os
import inspect

def relative_path(*paths):
    return os.path.join(os.path.dirname(__file__), *paths)

def relative_to_caller(*paths):
    frm = inspect.stack()[1]
    mod = inspect.getmodule(frm[0])
    return os.path.join(os.path.dirname(mod.__file__), *paths)

if __name__ == '__main__':
    print(relative_path('index.html'))

子/ sub_file.py

import sys
sys.path.append(r'/Users/xx/PythonScripts/!scratch')

import file1

if __name__ == '__main__':
    print(file1.relative_path('index.html'))
    print(file1.relative_to_caller('index.html'))

运行sub_file.py会给出以下输出:

/Users/xx/PythonScripts/!scratch/index.html
/Users/xx/PythonScripts/!scratch/sub/index.html

上述链接中的问题评论中有一些注意事项......

答案 1 :(得分:0)

请注意,跟踪堆栈在这里是可能的,但它可能会导致一些严重的麻烦(比如混淆'垃圾收集器',或者甚至可能不能用于鸡蛋)

我认为最干净的方法是将调用者传递给rel_path函数。

然而,正如您所知,在python中通常会有一种丑陋的做法。你可以这样做:

考虑遵循以下两个脚本:

# relpath.py

import os


def rel_path(path):
    if os.path.isfile(__name__):
        return os.path.relpath(path, start=__name__)

    print("Warning: %s is not a file: returning path relative to the current working dir" % __name__, file=sys.stderr)
    return os.path.relpath(path)


# caller.py

import importlib.util


spec = importlib.util.spec_from_file_location(name=__file__, location="/workspace/relpath.py")

rel =  importlib.util.module_from_spec(spec)

spec.loader.exec_module(rel)
print(rel.rel_path("/tmp"))

我们在这里做了什么:当使用importlib.util加载模块时,我们传递了name=__file__,它为我们的模块提供了由调用者脚本 path 组成的名称。因此,我们不需要将它作为参数传递给 relpath.py

请注意,这是干净的解决方案,对于将来阅读代码的开发人员来说可能不是可读。我只想展示python的可能性。