You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python C Extension如何获取用户模块所在目录及当前工作目录

解决方案

首先明确核心误区:你要获取的是调用你扩展接口的用户模块所在目录,而非进程当前工作目录——后者是Python进程启动时的目录,和用户模块存储位置无直接关联,这也是你之前思路的主要偏差点。

Python C API 没有单独封装路径获取的专用C函数,但你可以直接通过C API调用Python原生的inspect、os.path模块实现需求,两种可行实现方案如下:

方案1:纯C扩展层面直接实现

核心逻辑是通过C API获取调用栈信息,拿到调用方模块的__file__属性后解析目录,示例代码如下:

#include <Python.h>
#include <osdefs.h>

static PyObject* get_caller_dir(void) {
    // 导入inspect模块
    PyObject* inspect_mod = PyImport_ImportModule("inspect");
    if (!inspect_mod) return NULL;

    // 调用inspect.stack()获取调用栈
    PyObject* stack = PyObject_CallMethod(inspect_mod, "stack", NULL);
    if (!stack) {
        Py_DECREF(inspect_mod);
        return NULL;
    }

    // 取调用栈的第二层(第一层是当前C扩展函数本身,第二层是调用它的用户代码)
    PyObject* frame_info = PyList_GetItem(stack, 1);
    if (!frame_info) {
        Py_DECREF(stack);
        Py_DECREF(inspect_mod);
        return NULL;
    }
    PyObject* frame = PyTuple_GetItem(frame_info, 0);
    if (!frame) {
        Py_DECREF(stack);
        Py_DECREF(inspect_mod);
        return NULL;
    }

    // 获取frame的f_globals属性里的__file__
    PyObject* f_globals = PyObject_GetAttrString(frame, "f_globals");
    PyObject* file_path = PyDict_GetItemString(f_globals, "__file__");
    if (!file_path) {
        Py_DECREF(f_globals);
        Py_DECREF(stack);
        Py_DECREF(inspect_mod);
        return NULL;
    }

    // 调用os.path.dirname获取目录
    PyObject* os_mod = PyImport_ImportModule("os.path");
    PyObject* dir_path = PyObject_CallMethod(os_mod, "dirname", "O", file_path);

    // 清理引用
    Py_DECREF(os_mod);
    Py_DECREF(f_globals);
    Py_DECREF(stack);
    Py_DECREF(inspect_mod);

    return dir_path;
}

拿到目录路径后,把用户传入的相对路径和目录拼接即可得到完整的图片路径。

方案2:增加Python层包装(更推荐)

C扩展只负责接收绝对路径加载图片,你额外提供一层Python封装接口,在Python层完成路径解析:

# 这是你随C扩展一起发布的Python包装模块
import os
import inspect
from your_c_ext import load_image as _load_image

def load_image(img_path: str) -> Image:
    if not os.path.isabs(img_path):
        # 获取调用方模块所在目录
        caller_frame = inspect.stack()[1]
        caller_module_path = caller_frame.filename
        caller_dir = os.path.dirname(os.path.abspath(caller_module_path))
        img_path = os.path.join(caller_dir, img_path)
    return _load_image(img_path)

这个方案代码更易维护,出错概率更低,性能损耗完全可以忽略。


内容的提问来源于stack exchange,提问作者GreyHope

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 21:39:02