【问题标题】:IPython autoreload changes in subdirectory子目录中的 IPython 自动重载更改
【发布时间】:2015-10-13 15:24:03
【问题描述】:

我从主文件夹 /project 启动 IPython。现在,如果我在文件/project/tests/some_module.py 中进行更改,更改将无法在 IPython 中自动重新加载。此外,我在保存更改并希望在提示符中运行其他脚本后收到以下消息:

[autoreload of some_module failed: Traceback (most recent call last):
  File "/usr/lib/python2.7/dist-packages/IPython/extensions/autoreload.py", line 229, in check
    superreload(m, reload, self.old_objects)
ImportError: No module named some_module]

它似乎检测到在文件夹 /tests 内进行了更改,但它无法导入它。有人可以帮我解决这个问题吗?

编辑: 为了更好地说明:我从主文件夹中的终端启动 IPython。在这个文件夹中,我有另一个文件夹tests。在tests里面我有两个python文件:

some_module.py:

def hello_world():
  print "Hello World!!!"

use_some_module.py:

from some_module import hello_world

hello_world()

一旦我启动了 IPython,some_module.py 中的进一步更改将不会加载到 IPython 中。例如,如果我在hello_world() 的定义中添加第二个print "Hello Earth!!!",然后运行run tests/use_some_module.py,我会得到上面显示的错误消息,并且只会得到"Hello World!!!" 打印。

Edit2:我想要一个不需要更改工作目录或手动添加任何搜索路径的解决方案。我希望它通过 autoreload 自动加载。

【问题讨论】:

  • 第一次如何导入你的模块?您是否在首次导入和重新加载之间更改工作目录?
  • 来自Edit2的@michael,错误ImportError: No module named some_module表示autoreload模块的superreload函数找不到some_module,因为some_module不在搜索路径中。
  • @NizamMohamed 如果我退出 ipython 并在同一个父目录中重新启动它,更改会更新。
  • @NizamMohamed 所以,我想要的是它在每次tests/ 发生变化时自动执行此操作。我已经在我的 ipython 配置文件中添加了autoreload 2,它可以在我启动 ipython 的同一目录中完成更改工作,但它无法完成对子目录中的更改的工作。我想要一个可以添加到我的 ipython 配置文件中的解决方案,以便它自动执行。
  • 我已经更新了我的答案。

标签: python ipython


【解决方案1】:

如果您只需要在 Python 中重新加载已更改的文件,只需执行以下操作:

from main import some_module
....
reload(some_module)

但如果你的重载目的非常迫切,你可以执行以下操作(取自this question):

%load_ext autoreload
%autoreload 2

之前的代码每次执行新行之前都会重新加载所有更改的模块。

注意:您还可以检查 dreload 递归重新加载模块,以及 %run 允许您运行任何 python 脚本并将其所有数据直接加载到交互式命名空间。

希望对你有帮助,

【讨论】:

    【解决方案2】:

    模块/project/tests/some_module.py 必须可以从/project 导入。这意味着/project/tests 必须在sys.path 中。

    要么更改为/project/tests 和%run use_some_module.py,要么执行sys.path.insert(0,tests) 以将tests 插入到模块搜索路径中。

    如果some_module 不在搜索路径中,IPython 的autoreload 永远不会找到它。

    使其工作的另一种方法是通过在其中创建__init__.py 来将tests 制作成一个包。并在use_some_module 中使用相对导入作为from .some_module import hello_world。现在从 IPython 提示符下执行这些操作,

    In [1]: load_ext autoreload
    
    In [2]: %autoreload 2
    
    In [3]: from tests import some_module
    
    In [4]: run -m tests.use_some_module
    Hello World!!!
    In [5]: ed tests/some_module.py
    "tests/some_module.py" 3L, 69C written
     done. Executing edited code...
    In [6]: run -m tests.use_some_module
    Hello World!!!
    Hello World!!!  
    

    这就是你必须在tests 包中作为脚本运行use_some_module 模块。

    您第一次执行%run tests/use_some_module.py,就像您在运行python tests/use_some_module.py 一样运行。所以脚本所在的/project/tests 会自动包含在sys.path 中。这就是from some_module import hello_world 中的use_some_module 成功的原因。此外,运行后,use_some_module 的全局命名空间中的对象在 IPython 会话中可用。

    但是当您更改tests/some_module 时,必须再次加载它才能看到更改。要手动reload,必须先导入。现在import 应该成功了,因为use_some_module 在运行时首先导入了它,some_module 在sys.modules 中。但是reload 要成功,some_moudle 必须在搜索路径中。因此,即使手动 reload 也会失败,更不用说 autoreload。

    In [2]: #before %run  
    In [3]: 'some_module' in globals()
    Out[3]: False
    
    In [6]: 'some_module' in sys.modules
    Out[6]: False
    
    In [7]: 'hello_world' in globals()
    Out[7]: False
    
    In [8]: run tests/use_some_module.py
    Hello World!!!
    
    In [9]: 'some_module' in globals()
    Out[9]: False
    
    In [11]: 'some_module' in sys.modules
    Out[11]: True
    
    In [12]: 'hello_world' in globals()
    Out[12]: True
    In [13]: import some_module
    
    In [14]: some_module = reload(some_module)
    ---------------------------------------------------------------------------
    ImportError                               Traceback (most recent call last)
    <ipython-input-14-47e3c0de23e1> in <module>()
    ----> 1 some_module = reload(some_module)
    
    ImportError: No module named some_module
    

    另一种解决方案是以PYTHONPATH=tests ipython 启动IPython,以在sys.path 中包含tests 目录。
    或将此c.InteractiveShellApp.exec_lines = ['import sys','sys.path.insert(0,"tests")'] 设置为ipython_config.py。
    .

    【讨论】:

    • 感谢您的回复。我是 Python 的新手,所以我不确定我是否完全理解它。为什么 autoreload 不够聪明,无法在与我正在运行的文件相同的路径中查找? (即tests/)。我的意思是,它在第​​一个 run 中执行此操作,但后来不再执行此操作。顺便说一句:我没有对你投反对票。
    • 查看search path 了解更多信息。我已经回答了你的问题。第一次运行从some_module 导入hello_world。同一会话的后续运行不会重新导入已导入的模块。这就是为什么我们需要reload。但是reload 看不到不在搜索路径中的模块。您必须告诉它在某些路径中查找。 autoreload 是 reload 的自动版本。 autoreload 和 %run 是两个不同的东西。 %run 是 IPython 运行外部模块的机制。
    • 不能像%run 那样在sys.path 中自动包含reload 中的tests/ 吗?
    • %run 使用execfile。检查execfile 和reload 的语法。 execfile 使用路径名 reload 使用已加载的模块名称。
    • 跟踪了一切,但没有任何效果。有什么建议吗?
    【解决方案3】:

    尝试将您的文件 use_some_module.py 更改为:

    import some_module
    
    some_module.hello_world()
    

    使用from import 重新加载通常不起作用。

    这对我有用:

    %autoreload 1
    %aimport use_some_module
    %aimport some_module
    

    【讨论】:

    • 不走运。你能复制我的问题吗?
    猜你喜欢
    • 2014-07-29
    • 2016-04-02
    • 2018-02-22
    • 1970-01-01
    • 1970-01-01
    • 2010-12-26
    • 1970-01-01
    • 2013-03-18
    • 1970-01-01
    相关资源
    最近更新 更多