【问题标题】:Proper way to reload a python module from the console从控制台重新加载 python 模块的正确方法
【发布时间】:2011-02-01 19:57:36
【问题描述】:

我正在从 python 控制台进行调试,并且希望每次进行更改时都重新加载一个模块,这样我就不必退出控制台并重新输入它。我在做:

>>> from project.model.user import *
>>> reload(user)

但我收到:

>>>NameError: name 'user' is not defined

重新加载整个用户类的正确方法是什么?有没有更好的方法来做到这一点,也许在调试时自动更新?

谢谢。

【问题讨论】:

    标签: python


    【解决方案1】:

    如你所问,你能做的最好的就是

    >>> from project.models.user import *
    >>> import project # get module reference for reload
    >>> reload(project.models.user) # reload step 1
    >>> from project.models.user import * # reload step 2
    

    如果您直接使用用户模块,而不是使用import *(这几乎不是正确的做法),那会更好更干净。那么它只是

    >>> from project.models import user
    >>> reload(user)
    

    这会做你想做的事。但是,它不是很好。如果你真的需要如此频繁地重新加载模块,我不得不问:为什么?

    我的怀疑(以前有人问过类似问题的经验证实了这一点)是您正在测试您的模块。有很多方法可以测试模块,而在交互式解释器中手动测试是最糟糕的方法之一。将您的一个会话保存到一个文件并使用doctest 进行快速修复。或者,将其写为程序并使用python -i。不过,唯一真正出色的解决方案是使用 unittest 模块。

    如果不是这样,希望它会更好,而不是更糟。 reload 确实没什么用处(事实上,它在 3.x 中已被删除)。它不能有效地工作——你可能会重新加载一个模块,但会留下以前版本的剩余部分。它甚至不适用于所有类型的模块——扩展模块在重新加载时无法正确重新加载,有时甚至会严重损坏。

    在交互式解释器中使用它的上下文不会留下很多关于您正在做什么以及真正的最佳解决方案是什么的选择。在它之外,有时人们使用reload() 来实现插件等。这充其量是危险的,并且经常可以使用exec(我们发现自己所处的邪恶领域)或隔离过程以不同的方式完成。

    【讨论】:

    • 我正在做的是找到这个问题,我正在使用控制台来探索从 JSON 导入的数据结构。我想使用“重新加载”在我的文本编辑器中保留一些功能,这些功能以不同的方式遍历结构,编辑它们,然后重新运行它们,而不必退出控制台。尽管如此,如果 Python 不能干净地支持这一点,出于实现原因,例如无法删除“剩菜”,我想我想这样做一定是错的;-p +1 的答案让我无论如何都可以这样做,不过。
    • +1 向我展示了我应该,真的,真的,写测试而不是在解释器中手工做事,即使是为了微调。这对于未来的非回归测试也很有用。
    • 您很少会看到我反对单元测试,但是当您进行原型设计时,肯定会有这样的场景很有价值。不同意整体情绪,但“最糟糕的方式之一”是一种非常严格的价值判断。
    • 天真地对待 medwards。我在 python 调试器中使用 reload 在 b/c 中找到了我的方式。在调试可编辑包时,我希望修改和重新加载模块并调用有问题的例程,而不是每次都退出 python 并从头开始。为什么这不是 reload() 的有效和使用?场景与单元测试无关。
    • 3.x 不断重新加载。它只是将其移出内置函数:stackoverflow.com/questions/961162/…
    【解决方案2】:

    对于 python3,reload 已移至 imp 模块。你可以使用imp.reload()。您可以参考this post

    >>> import imp
    >>> import project # get module reference for reload
    >>> imp.reload(project.models.user) # reload step 1
    >>> from project.models.user import * # reload step 2
    

    【讨论】:

    【解决方案3】:

    IPython 可以在执行每个新行之前重新加载模块:

    %load_ext autoreload
    %autoreload 2
    

    %autoreload 2reloads “每次执行键入的 Python 代码之前,所有模块(%aimport 排除的模块除外)。”

    查看文档:

    【讨论】:

      【解决方案4】:

      你不能以有效的方式使用 reload()。

      Python 不提供对重新加载或卸载以前导入的有效支持 模块;模块引用使得重新加载模块变得不切实际,因为引用可能存在于程序的许多地方。

      Python 3 完全移除了 reload() 功能。

      【讨论】:

      • 不是模块引用做的:reload() 实际上改变了模块对象。破坏事物的是模块内对函数和类的引用(特别是由 from foo import * 生成的引用)。
      • 是的,我同意,你可以有其他程序模块已经导入了你想要卸载的模块。
      【解决方案5】:

      不幸的是,您必须使用:

      >>> from project.model import user
      >>> reload(user)
      

      我不知道有什么东西会在交互式提示下自动重新加载模块……但我看不出有任何理由不应该存在(事实上,这不会太难实施,要么……)

      现在,你可以做这样的事情:

      from types import ModuleType
      import sys
      _reload_builtin = reload
      def reload(thing):
          if isinstance(thing, ModuleType):
              _reload_builtin(thing)
          elif hasattr(thing, '__module__') and thing.__module__:
              module = sys.modules[thing.__module__]
              _reload_builtin(module)
          else:
              raise TypeError, "reload() argument must be a module or have an __module__"
      

      【讨论】:

        【解决方案6】:

        你也可以试试twisted.python.rebuild.rebuild

        【讨论】:

          【解决方案7】:
              from test_reload import add_test
          

          test_reload 是一个模块,add_test 是一个函数 如果你改变了函数add_test,当然你需要重新加载这个函数。 那么你可以这样做:

          
              import imp
              imp.reload(test_reload)
              from test_reload import add_test
          

          这将刷新函数add_test

          所以你需要添加

          imp.reload(test_reload)
          from test_reload import add_test  --add this line in your code
          

          【讨论】:

          • 如果您添加一些信息来解释您的答案/代码会更好。
          【解决方案8】:

          从 Python 3.4 开始,您可以使用 importlib.reload(module)

          >>> from importlib import reload
          >>> from project.model import user
          >>> reload(user)
          

          【讨论】:

            猜你喜欢
            • 2017-03-18
            • 2012-10-15
            • 2011-09-15
            • 1970-01-01
            • 2020-06-11
            • 1970-01-01
            • 1970-01-01
            • 2016-07-23
            • 2016-05-25
            相关资源
            最近更新 更多