【问题标题】:recursive reload() "from some_module import *" in pythonpython中的递归reload()“来自some_module import *”
【发布时间】:2014-07-21 01:54:14
【问题描述】:

我有一个名为 KosmoSuite 的模块,按照 __init__.py 进行了初始化

...
from chemical_fuels import *
from orbital_mechanics import *
from termodynamics import *
from rail_guns import *
...

在文件chemical_fuels.py, orbital_mechanics.py, termodynamics.py, rail_guns.py 中包含一些数据表、常数和用于进行一些物理计算的函数(例如函数orbital_mechanics.escape_velocity(M,R) 用于计算从给定质量和半径的行星的逃逸速度)

我想使用 python 解释器作为空间相关问题的交互式计算器。

但是,问题在于交互式开发和调试。当我这样做时

>>> import KosmoSuite as ks
# ... modify something in orbital_mechanics.escape_velocity( ) ...
>>> reload(ks)
>>> ks.orbital_velocity( R, M)

但是ks.orbital_velocity( R, M) 不受我对orbital_mechanics.escape_velocity() 的修改的影响。 reload(ks) 是否有其他替代方法可以完成这项工作(即重新加载由from some_module import * 递归导入的所有对象、常量和函数)

更好的是像

>>> from KosmoSuite import *
# ... modify something in orbital_mechanics.escape_velocity( ) ...
>>> from KosmoSuite reimport *
>>> orbital_velocity( R, M)

脚注:我现在正在使用 Spyder ( Python(x,y) ),但默认的 Python 解释器也是如此。在this question 中是关于IPython 中的deep-reload (dreload)。我不确定它是否能完成这项工作,但无论如何我都不喜欢 IPython。

【问题讨论】:

    标签: python python-import spyder


    【解决方案1】:

    在 Python 中重新加载模块并不能如您所愿。一旦你创建了一个对象ks,它就会引用类,因此也引用了代码。如果您重新加载一个模块,它将定义一个与原始类同名的新类。该对象仍然引用原始类,而不是新类。

    您可能能够更改现有对象的类,但如果它们引用其他对象,那么您必须尝试更改这些类等。您将与类和模块系统作斗争,试图重新- 自己实现重载的重要部分。

    您最好找到一个与 Python 模块的行为方式一致的工作流。 IPython notebook 允许您以交互方式进行试验,但捕获代码以便可以从顶部重新运行。可能还有其他解决方案。

    【讨论】:

      【解决方案2】:

      可以说,一个非常严厉的解决方案是在导入模块链之前保存sys.modules的状态,然后在再次导入模块之前将其恢复到原始状态。

      import sys
      bak_modules = sys.modules.copy()
      import KosmoSuite as ks
      # do stuff with ks
      # edit KosmoSuite
      for k in sys.modules.keys():
          if not k in bak_modules:
              del sys.modules[k]
      import KosmoSuite as ks
      

      但是,有一些警告:

      1. 您可能需要重新导入同时导入的不相关模块。
      2. 如果您使用旧版本的模块创建了任何对象,它们将保留其旧类。

      不过,我在开发模块时使用它,同时在交互式会话中测试它,如果考虑到限制,它在大多数情况下都可以正常工作。

      【讨论】:

      • 听起来不错,但我得到了错误:bak_modules = sys.modules[:] Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: unhashable type ... 可能是因为我使用的是 python 2.7 或 spyder?
      • 对不起,我是凭记忆去的。您需要使用 sys.modules.copy() 并明确删除密钥才能使其工作。我已经更新了答案。
      【解决方案3】:

      是的,只要 Python 支持元编程,就可以做到。

      这是我执行此类任务的函数的变体 (Python3):

      import importlib, sys
      
      def reload_all(top_module, max_depth=20):
          '''
          A reload function, which recursively traverses through
          all submodules of top_module and reloads them from most-
          nested to least-nested. Only modules containing __file__
          attribute could be reloaded.
      
          Returns a dict of not reloaded(due to errors) modules:
            key = module, value = exception
          Optional attribute max_depth defines maximum recursion
          limit to avoid infinite loops while tracing
          '''
          module_type = type(importlib)   # get the 'module' type
          for_reload = dict() # modules to reload: K=module, V=depth
      
          def trace_reload(module, depth):    # recursive
              nonlocal for_reload
              depth += 1
              if type(module) == module_type and depth < max_depth:
                  # if module is deeper and could be reloaded
                  if (for_reload.get(module, 0) < depth
                      and hasattr(module, '__file__') ):
                          for_reload[module] = depth
                  # trace through all attributes recursively       
                  for name, attr in module.__dict__.items():
                      trace_reload(attr, depth)
      
      
          trace_reload(top_module, 0)         # start tracing
          reload_list = sorted(for_reload, reverse=True,
                               key=lambda k:for_reload[k])
          not_reloaded = dict()
          for module in reload_list:
              try:
                  importlib.reload(module)
              except:     # catch and write all errors
                  not_reloaded[module]=sys.exc_info()[0]
      
          return not_reloaded
      

      自我记录就足够了。 如果你有一些改进的想法,可以参考这里的 github 项目:https://github.com/thodnev/reload_all

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-03-08
        • 2020-11-29
        • 2014-08-28
        • 2014-11-30
        • 2019-09-24
        • 2021-08-25
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多