【问题标题】:Get relative path of caller in Python在Python中获取调用者的相对路径
【发布时间】:2015-01-19 09:32:36
【问题描述】:

我有这个功能:

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

如何更改它以返回相对于调用者的路径?

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

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

【问题讨论】:

  • 这些路径是否严格以调用者的目录开头?
  • 您是在问如何确定调用者所在的脚本的路径吗?如果不是,调用者的路径是什么?
  • 我不知道如何比“获取调用者的相对路径”更清楚。你能解释一下为什么不清楚吗?
  • 为什么需要神奇地使用父文件位置?为什么不更明确地说明路径的基础? Flask 要求您使用当前模块名称 (app = Flask(__name__)) 创建 Flask() 对象,以便它可以查找加载模板的路径 (sys.modules[name_passed_in].__file__)。这使它显式并且还允许您覆盖路径。不需要神奇的调用者查找。

标签: python path


【解决方案1】:

调整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/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

对于上面链接中的问题,cmets 中有一些警告......

【讨论】:

    【解决方案2】:

    请注意,在这里跟踪堆栈是可能的,但它可能会导致一些严重的问题(比如混淆“垃圾收集器”,或者甚至可能无法在鸡蛋中工作)

    我相信最干净的方法是将调用者传递给 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__,它为我们的模块提供了由调用者脚本路径组成的名称。因此我们不需要将它作为参数传递给 relpath.py

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

    【讨论】:

      猜你喜欢
      • 2019-03-30
      • 1970-01-01
      • 2019-06-21
      • 1970-01-01
      • 2012-01-02
      • 1970-01-01
      • 1970-01-01
      • 2011-02-07
      • 2012-10-25
      相关资源
      最近更新 更多