python - 可靠获取调用函数的文件路径
问题描述
说我有一个功能foo()
。调用时,我希望该函数能够可靠地确定调用它的模块(或调用函数)的文件路径。问题是inspect
模块中的各种函数只返回相对路径(我假设是相对于导入时的工作目录)。但是,我的代码多次切换工作目录,我不知道有问题的工作目录。
import inspect
import os
def foo():
frame = inspect.stack()[0]
print(frame.filename)
print(os.path.abspath(frame.filename))
foo()
os.chdir("/")
print("New CWD:", os.getcwd())
foo()
输出:
$ cd ~
$ python3 foo.py
foo.py
/home/user/foo.py
New CWD: /
foo.py
/foo.py
通过我的 IDE 中的自动完成,我发现有一个未记录的函数inspect.getabsfile()
。不幸的是,这也不能可靠地工作:
import inspect
def foo():
print("Hello")
print(inspect.getabsfile(foo))
os.chdir("/")
print("New CWD:", os.getcwd())
print(inspect.getabsfile(foo))
输出:
$ cd ~
$ python3 foo.py
/home/user/foo.py
New CWD: /
/foo.py
如果我正确理解了这个错误报告,__file__
并且code.co_filename
(docs)(是?)将在某个时候(还没有发生)成为绝对路径。在此期间我能做些什么来解决这个问题?
更新:以上两个示例脚本的主要问题是它们访问源自主模块的对象/堆栈帧。只要从不同的模块导入对象或考虑存在于另一个模块中的函数的堆栈框架,它就可以工作。以类似的方式,在其他模块中__main__
,__file__
确实给出了绝对路径。(另请参阅Python 错误跟踪器中的这个问题。)不过,我不知道为什么对主模块进行不同的处理。
解决方案
通过使用closure
技术,您可以将脚本路径存储在import time中,因此只需检查函数是否来自__main__
就足以获取以下所有 3 种情况的路径:
from ~ import ~
import ~
- 主脚本中定义的对象
以下示例演示了所有 3 个:
from sys import modules
from os.path import abspath
from os import getcwd, chdir
from Module import a
import timeit
def closure():
original_working_dir = abspath(__file__) # store absolute path for linux
def _get_path(obj):
nonlocal original_working_dir
try:
return abspath(obj.__file__)
except AttributeError: # it's probably not a module
if obj.__module__ == '__main__': # check if module is same as local:
return abspath(original_working_dir)
return abspath(modules[obj.__module__].__file__)
return _get_path
get_path = closure()
def test_func():
pass
def test_output():
print(f"\nworking directory: {getcwd()}")
print(f"import from: {get_path(a)}")
print(f"simple import: {get_path(timeit)}")
print(f"local function: {get_path(test_func)}")
if __name__ == '__main__':
test_output()
chdir('/')
test_output()
窗口的输出:
working directory: Z:\github\StackOverFlow\63865883
import from: Z:\github\StackOverFlow\63865883\Module.py
simple import: C:\Users\--\AppData\Local\Programs\Python\Python38\lib\timeit.py
local function: Z:\github\StackOverFlow\63865883\63865883.py
working directory: Z:\
import from: Z:\github\StackOverFlow\63865883\Module.py
simple import: C:\Users\--\AppData\Local\Programs\Python\Python38\lib\timeit.py
local function: Z:\github\StackOverFlow\63865883\63865883.py
Ubuntu:
working directory: /mnt/z/github/StackOverFlow/63865883
import from: /mnt/z/github/StackOverFlow/63865883/Module.py
simple import: /usr/lib/python3.8/timeit.py
/mnt/z/github/StackOverFlow/63865883/63865883.py
local function: /mnt/z/github/StackOverFlow/63865883/63865883.py
working directory: /
import from: /mnt/z/github/StackOverFlow/63865883/Module.py
simple import: /usr/lib/python3.8/timeit.py
/mnt/z/github/StackOverFlow/63865883/63865883.py
local function: /mnt/z/github/StackOverFlow/63865883/63865883.py
您的代码不时正常工作的主要原因是因为__file__
主脚本的属性取决于您是使用相对路径还是绝对路径运行 python 脚本。
似乎__file__
主脚本存储从终端提供给 python 解释器的文件参数。
例如,运行此文件时:
print(__file__)
当通过相对调用时python3 scratch.py
:
scratch.py
你得到它的绝对路径。
使用绝对路径python3 /mnt/c/~~/scratches/scratch.py
:
/mnt/c/Users/--/AppData/Roaming/JetBrains/PyCharm2020.2/scratches/scratch.py
你得到完整的路径__file__
。
推荐阅读
- oracle - Oracle DB 到 Oracle DB Connection Connection forward
- java - Spring Data Elasticsearch 是否支持日期字段的多种日期格式
- django - 带有 Redis 代理和多个队列的 Celery:所有任务都注册到每个队列
- python - 在 python 中迭代 n 行数组,然后是下 n 行,依此类推
- c++ - C++朋友模板函数:找不到函数定义
- java - if语句循环
- c++ - C++ 内联 lambda 参数
- assembly - 为什么没有设置进位标志?
- javascript - 从另一个页面上的触发器加载页面后是否可以执行代码?JS
- websphere-liberty - 在 websphere liberty 中获取数据源连接