简体   繁体   English

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

[英]Get relative path of caller in Python

I've got this function: 我有这个功能:

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

How would I change it to return the path relative to the caller? 如何更改它以返回相对于调用者的路径

For example, if I called relative_path('index.html') from another script, is it possible to get the path relative the script from where it was called implicitly or would I need to modify relative_path to pass __file__ across as well like this? 例如,如果我从另一个脚本调用relative_path('index.html') ,是否可以从隐式调用它的位置获取相对于脚本的路径,或者我是否需要修改relative_path以传递__file__以及这样?

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

adapting the solution in Get __name__ of calling function's module in Python 在Python中调用函数模块的Get __name__中的解决方案

file1.py 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/sub_file.py 子/ 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'))

Running sub_file.py gives the following output: 运行sub_file.py会给出以下输出:

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

There are some caveats in the comments to the question in the link above... 在上面的链接中对问题的评论中有一些警告......

Note that tracing stack would be a possibility here, but it could cause some serious trouble ( like confusing 'garbage collector', or may not even work in eggs ) 请注意,跟踪堆栈在这里是可能的,但它可能会导致一些严重的麻烦(比如混淆'垃圾收集器',或者甚至可能无法在鸡蛋中工作)

I believe the cleanest way would be to pass the caller to the rel_path function. 我相信最干净的方法是将调用者传递给rel_path函数。

However, as you may know, there is usually an ugly way of doing things in python. 但是,正如您所知,在python中通常有一种丑陋的做法。 You can do for example something like this: 你可以这样做:

consider following two scripts: 考虑以下两个脚本:

# 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"))

What we did here: when loading the module using importlib.util, we passed the name=__file__ , which gave our module the name consisting of the caller script path . 我们在这里做了什么:当使用importlib.util加载模块时,我们传递了name=__file__ ,它为我们的模块提供了包含调用者脚本路径的名称。 Hence we needn't pass it as an argument to the relpath.py . 因此,我们不需要将它作为参数传递给relpath.py

Note that this is not clean solution and might not be readable for future developers reading your code. 请注意,这是干净的解决方案,可能无法读取为以后的开发人员阅读你的代码。 I just wanted to demonstrate the possibilities of python. 我只想展示python的可能性。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM