更新导入后如何重新加载导入?Sage 似乎直到会话结束才重新加载它

How to reload an import after updating it? Sage doesn't seem to reload it till end of session

提问人:user93353 提问时间:10/3/2023 最后编辑:Mark Rotteveeluser93353 更新时间:10/6/2023 访问量:44

问:

我有一个名为的文件,其中包含一个类。 我有一个将其导入为MyClass.pyMyClassMyPrg.sage

  from MyClass import MyClass

然后实例化并调用一个方法。MyClass

我通过调用 .如果在程序退出后,我更改并再次运行,它似乎使用较旧的.让它运行更新的类的唯一方法是杀死 shell 并在新的 shell 中运行它。MyPrg.sageloadMyClass.pyMyPrg.sageloadMyClass.py

有没有办法告诉 Sage 重新加载更新的导入?

我在Windows 10上运行Sage 9.3。

python-import 重新加载 sage

评论


答:

1赞 VonC 10/6/2023 #1

在 Python 中,importlib 模块可用于重新加载已导入的模块()。
但是,需要注意的是,重新加载模块并不总是那么简单,尤其是在处理对象定义时,因为现有对象不会自动更新以反映模块代码中的更改。
importlib.reload(module)

SageMath 中,您需要:

  • 将模块导入到文件中。importlibMyPrg.sage
  • 作为模块导入。MyClass
  • 用于在更新时重新加载模块。importlib.reload()MyClassMyClass.py

那是:

import importlib
import MyClass

# Load the module initially
my_class_instance = MyClass.MyClass()

# do something

# Now, assume MyClass.py has been updated, and you want to reload it:
importlib.reload(MyClass)

# Now when you create a new instance, it will reflect the updated code:
my_class_instance = MyClass.MyClass()

使用此设置,每次调用 时,Python 都会从 重新加载模块,以反映您对该文件所做的任何更改。importlib.reload(MyClass)MyClassMyClass.py


如前所述,任何现有的实例都不会更新;只有在重新加载模块创建的新实例才会反映更新的代码。MyClass

下面是一个示例来说明这一点:

假设最初如下所示:MyClass.py

class MyClass:
    def method(self):
        print("Old Method")

您有一个导入和创建实例的脚本:MyPrg.sageMyClass

from MyClass import MyClass

obj = MyClass()
obj.method()  # Outputs: Old Method

现在,您更新以更改:MyClass.pymethod

class MyClass:
    def method(self):
        print("New Method")

如果重新加载模块并调用现有实例,您仍将看到旧行为:MyClassmethodobj

import importlib
import MyClass

importlib.reload(MyClass)
obj.method()  # Outputs: Old Method

但是,如果您创建一个新实例 ,您将看到新行为:MyClass

new_obj = MyClass.MyClass()
new_obj.method()  # Outputs: New Method

这说明了现有对象如何保留其在重新加载模块之前的行为,而新对象则反映更新的类定义。


我想要的不是在做某事后重新加载。
我想在启动程序本身时重新加载。

  1. 我跑.MyPrg
  2. MyPrg完成执行
  3. 我更新.MyClass
  4. 我重新运行,旧的似乎仍然是运行的那个MyPrgMyClass

我的是.
我将其导入为“”。
我将其实例化为 .
MyClassMyClass.pyMyPrg.sagefrom MyClass import MyClassobj = MyClass()

在这之后,我得到”importlib(MyClass)TypeError: reload() argument must be a module"

当您执行 时,您将从模块导入类。
但是,当您尝试使用 时,它需要一个模块作为参数,而不是一个类。因此,您将收到一个 .
from MyClass import MyClassMyClassMyClass.pyimportlib.reload(MyClass)TypeError

处理导入的另一种方法是:importlib.reload()

  1. 修改 import 语句以导入模块,而不是直接从模块导入类。MyPrg.sageMyClass
  2. 然后,当您实例化时,您需要使用模块名称对其进行限定。MyClass
  3. 最后,您可以使用重新加载模块。importlib.reload()
import importlib
import MyClass  # Import the module, not the class

# Instantiate MyClass from the module
obj = MyClass.MyClass()

# Do something

# Assume MyClass.py has been updated and you want to reload it:
importlib.reload(MyClass)  # That will reload the module

# Now create a new instance, it will reflect the updated code:
new_obj = MyClass.MyClass()

这样,当您更改并重新运行时,该语句将重新加载更新的模块。
重新加载后创建的任何新实例都将反映更新后的代码。
该设置应处理您描述的场景,即您在运行之间进行更新,并希望在重新运行时使用更新的代码。
MyClass.pyMyPrg.sageimportlib.reload(MyClass)MyClassMyClassMyClass.pyMyPrg.sageMyPrg.sage


OP 在评论中补充道:

我不需要创建新对象,因为我正在重新运行程序。
因此,我只是在第一次创建对象之前调用,这足以在重新运行程序时刷新类。
importlibobj = MyClass.Class()

这意味着每次运行时都会调用 ,确保在创建对象实例之前加载最新版本的 。对于所描述的方案,这是一个简单而有效的解决方案,其中程序正在重新运行,并且希望确保使用最新版本。importlib.reload()MyPrg.sageMyClass.pyMyClass.py

这与我建议的不同:一种允许在正在运行的程序中重新加载模块的结构,这可能比所描述的场景所需的更多。

评论

0赞 user93353 10/6/2023
我想要的不是在做某事后重新加载。我想在启动程序本身时重新加载。1) 我运行 MyPrg。2) MyPrg 完成执行 3) 我更新 MyClass。4)我重新运行MyPrg,旧的MyClass似乎仍然是运行的MyClass
0赞 user93353 10/6/2023
我的 MyClass 已 MyClass.py。我在 MyPrg.sage 的顶部将其导入为“from MyClass import MyClass”。我将其实例化为 obj = MyClass()。在此之后,当我这样做时,importlib(MyClass),我得到“TypeError:reload()参数必须是一个模块”
0赞 VonC 10/6/2023
@user93353好的。我已经编辑了答案以解决您的评论。
0赞 user93353 10/6/2023
谢谢,如前所述,我不需要创建新对象,因为我正在重新运行程序。因此,我只是在第一次创建对象之前调用了importlib,这足以在重新运行程序时刷新类。obj = MyClass.Class()
0赞 VonC 10/6/2023
@user93353 简单有效,干得好!我已将您的评论包含在答案中以提高知名度。