如何强制 Python ScriptEngine 刷新其导入模块的缓存?

问题描述 投票:0回答:1

我在 Java 应用程序中使用 Python ScriptEngine 来执行导入各种其他 Python 脚本的 Python 脚本。

主脚本成功完成并且 eval 方法返回后,我将引擎对象引用设置为 null 并调用垃圾收集器。

接下来,我去编辑主脚本导入的脚本之一并保存它。

接下来,我像以前一样通过创建一个新的 ScriptEngine 对象并调用 eval 来运行该方法来执行主 Python 脚本,但是当主脚本运行时,它不会拾取我对导入脚本所做的更改。

显然导入的脚本被某些东西(也许是 Jython?)缓存在某处。

我不想在Python脚本中调用reload。必须有一种方法来告诉正在执行缓存的内容,以刷新或清除自身。

有人找到解决这个问题的方法吗? 我在 Windows 7 上使用 NetBeans 8.0.2、Java 1.8 update 45 和 Jython 2.7。这是 java 代码。 除了 import 语句之外,Python 脚本包含什么并不重要。

ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
ScriptEngine engine = scriptEngineManager.getEngineByName("python");
Object result = engine.eval();
engine = null;
System.gc();
java python netbeans jython scriptengine
1个回答
0
投票

在您的场景中,您在 Java 应用程序中使用 Python ScriptEngine(可能是 Jython)。您面临的问题是,尽管清除了引擎并进行了垃圾收集,但在修改底层 Python 脚本后,导入的 Python 模块并未重新加载。

出现此行为是因为 Python(在本例中是通过 Jython)缓存导入的模块以提高性能。即使您销毁并重新创建 ScriptEngine 对象,导入的模块仍可能缓存在底层 Python 运行时中。

以下是问题的细分和潜在的解决方案:

根本原因

在 Jython 中导入 Python 脚本时,它通常会缓存在模块系统中,以避免多次重新加载。 简单地重新初始化 ScriptEngine 不一定会清除此缓存,因为它是由 Jython 内部管理的。 解决方案 要强制 Jython 重新加载模块,您可以在重新运行脚本之前显式清除模块缓存。您可以通过访问 Jython 的内部 sys.modules 字典并删除缓存的模块来完成此操作。当您再次运行脚本时,这将强制 Jython 从文件系统重新加载模块。

代码示例

import javax.script.*;
import org.python.util.PythonInterpreter;
import org.python.core.*;

public class PythonScriptEngineExample {
    public static void main(String[] args) throws Exception {
        // Create a new ScriptEngineManager and ScriptEngine for Python
        ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
        ScriptEngine engine = scriptEngineManager.getEngineByName("python");

        // Run the script (initial execution)
        engine.eval("import mymodule"); // Replace with your script logic
        engine = null; // Drop reference to the engine
        
        // Force garbage collection
        System.gc();
        
        // Before re-running, clear the cached modules
        clearPythonCache();
        
        // Create a new ScriptEngine and re-run the script (with the updated module)
        engine = scriptEngineManager.getEngineByName("python");
        engine.eval("import mymodule"); // Again, replace with your script logic
    }
    
    private static void clearPythonCache() {
        // This method forces Jython to reload all modules by clearing sys.modules
        try (PythonInterpreter interpreter = new PythonInterpreter()) {
            interpreter.exec("import sys");
            interpreter.exec("sys.modules.clear()"); // Clears the module cache
        }
    }
}

说明:

clearPythonCache()
方法: 此方法使用 Jython 中的 PythonInterpreter(这是与 Python 运行时交互的更直接的方式)来清除 sys.modules 缓存。 sys.modules 是一个字典,保存当前 Python 会话中所有导入的模块。通过清除此字典,Jython 会将每个导入视为全新导入,强制它从文件系统重新加载脚本。 重新运行脚本:清除缓存后,下次运行脚本(通过engine.eval())时,导入应该反映最新的更改。

补充说明: 此解决方案假设您有权访问 Jython 的 PythonInterpreter 类,它是 Jython 运行时的一部分。 ScriptEngine API 不提供对 sys.modules 的直接访问,因此您需要使用 PythonInterpreter 在较低级别操作 Python 环境。 sys.modules 上的clear() 方法会删除所有已加载的模块,因此 Jython 将在下次导入这些模块时重新加载这些模块。 这应该有助于解决从 Java 应用程序使用 Jython 时模块缓存的问题。

© www.soinside.com 2019 - 2024. All rights reserved.