如何在 Python 解释器中重新导入更新的包? [复制]

Posted

技术标签:

【中文标题】如何在 Python 解释器中重新导入更新的包? [复制]【英文标题】:How to re import an updated package while in Python Interpreter? [duplicate] 【发布时间】:2010-10-15 14:41:20 【问题描述】:

我经常在 Python Interpreter 中测试我的模块,当我看到错误时,我会快速更新 .py 文件。但是我如何让它反映在解释器上?所以,到目前为止,我一直在退出并重新进入解释器,因为重新导入文件对我不起作用。

【问题讨论】:

看起来这个问题是在重新导入发布之前提出/回答的。请参阅下面的答案以获取新信息。 Python 中的导入是缓存的,因此即使文件已更改,通常第二次和后续导入也会得到相同的代码。 【参考方案1】:

Python3 的更新:(引自already-answered answer,因为此处的最后编辑/评论建议使用已弃用的方法)

在 Python 3 中,reload 已移至 imp 模块。在 3.4 中,imp 被弃用,取而代之的是 importlibreload 被添加到后者。面向 3 或更高版本时,请在调用 reload 时引用相应的模块或将其导入。

外卖:

Python3 >= 3.4:importlib.reload(packagename) Python3 imp.reload(packagename) Python2:在下面继续

使用reload 内置函数:

https://docs.python.org/2/library/functions.html#reload

reload(module)被执行时:

重新编译 Python 模块的代码并重新执行模块级代码,定义一组新的对象,这些对象绑定到模块字典中的名称。扩展模块的init函数不会被第二次调用。 与 Python 中的所有其他对象一样,旧对象仅在其引用计数降至零后才会被回收。 模块命名空间中的名称已更新,以指向任何新的或更改的对象。 对旧对象的其他引用(例如模块外部的名称)不会重新绑定以引用新对象,如果需要,必须在它们出现的每个命名空间中进行更新。

例子:

# Make a simple function that prints "version 1"
shell1$ echo 'def x(): print "version 1"' > mymodule.py

# Run the module
shell2$ python
>>> import mymodule
>>> mymodule.x()
version 1

# Change mymodule to print "version 2" (without exiting the python REPL)
shell2$ echo 'def x(): print "version 2"' > mymodule.py

# Back in that same python session
>>> reload(mymodule)
<module 'mymodule' from 'mymodule.pyc'>
>>> mymodule.x()
version 2

【讨论】:

注意reload只重新加载指定的模块;该模块的导入也必须单独重新加载。 另请注意,任何引用模块中任何内容的对象(例如在模块中定义其类的实例)将继续使用旧的、预重载的东西。一般来说,重新启动解释器是最干净的方法。 重新加载现在不再是 Python 3 中的一个功能。改用 imp.reload() reload() 无法可靠地重新加载包或***模块导入的任何模块。 是否有类似的方式使用 reload 语句,例如:from src imort func as f ?【参考方案2】:

以上关于reload()imp.reload() 的所有答案均已弃用。

reload() 不再是 python 3 中的内置函数,imp.reload() 被标记为已弃用(请参阅help(imp))。

最好改用importlib.reload()

【讨论】:

谢谢。我不明白为什么这个答案没有赞成票。其他解决方案均不适用于 Python 3.4。 请注意,这需要一个 module 对象作为其参数,而不是 str 这对我不起作用。我在 repl 中收到一条消息,说该模块没有类似的方法。 问题是你必须先导入importlib。所以在做import importlib之后,你可以再做importlib.reload(some_module) 这对我有用,但通常不是一开始。我的错误是我一直忘记我做了类似“import bigfancything as bft”然后尝试做“importlib.reload(bigfancything)”。你会认为像我这样的懒人会先尝试更短更正确的“importlib.reload(bft)”,但事实并非如此。【参考方案3】:

所以,到目前为止,我一直在退出并重新进入解释器,因为重新导入文件对我不起作用。

是的,只要再说一次import,就可以得到来自sys.modules 的模块的现有副本。

您可以说reload(module) 来更新sys.modules 并获取该单个模块的新副本,但如果任何其他模块引用了原始模块或原始模块中的任何对象 ,他们将保留旧的参考资料,并且会发生非常令人困惑的事情。

因此,如果您有一个模块 a,它依赖于模块 b,并且 b 发生变化,您必须先“重新加载 b”,然后再“重新加载 a”。如果你有两个相互依赖的模块,当这些模块是同一个包的一部分时,这是非常常见的,你不能同时重新加载它们:如果你重新加载p.a,它将获得对旧的引用p.b,反之亦然。唯一的方法是通过从sys.modules 中删除它们的项目来一次卸载它们,然后再次导入它们。这很棘手,并且有一些实际的陷阱与模块条目为 None 作为失败的相对导入标记有关。

如果您有一个模块将对其对象的引用传递给系统模块 — 例如,它注册了一个编解码器,或者添加了一个警告处理程序 — 你被卡住了;你不能在不混淆 Python 环境的其余部分的情况下重新加载系统模块。

总而言之:除了一个独立脚本加载一个自包含模块的最简单情况外,reload() 很难正确处理;如果,正如你所暗示的,你正在使用一个“包”,你可能会更好地继续循环解释器。

【讨论】:

但是,如果您正在谈论一个测试用例和一个不断变化的单元测试脚本,那么在 sut 上运行 reload 应该可以正常工作。事实上,如果添加“重新加载(sut 模块)”应该是我在单元测试中作为标准包含的内容,我正在徘徊。【参考方案4】:

在 Python 3 中,行为发生了变化。

>>> import my_stuff

...用 my_stuff 做点什么,然后:

>>>> import imp
>>>> imp.reload(my_stuff)

你会得到一个全新的、重新加载的 my_stuff。

【讨论】:

在 Python 3.4 中,imp 已被弃用,取而代之的是 importlibimportlib.reload(my_stuff)【参考方案5】:

无论您导入一个模块多少次,您都会从sys.modules 获得相同的模块副本 - 最初是在import mymodule 加载的

我回答得这么晚了,因为上面/之前的每个答案都有一些答案,所以我试图将它们总结在一个答案中。

使用内置函数

对于 Python 2.x - 使用内置的 reload(mymodule) 函数。

对于 Python 3.x - 使用 imp.reload(mymodule)

对于 Python 3.4 - 在 Python 3.4 中,imp 已被弃用,取而代之的是 importlib,即importlib.reload(mymodule)

几点注意事项

内置或动态重新加载一般不是很有用 加载的模块。重载sys__main__builtins等key 不推荐使用模块。 在许多情况下,扩展模块不是 设计为不止一次初始化,并且可能会在任意情况下失败 重新加载时的方式。如果一个模块从另一个模块导入对象 使用from ... import ...,为另一个模块调用reload() 不要重新定义从中导入的对象——解决这个问题的一种方法是 重新执行from语句,另一种是使用import并限定 名称 (module.name) 代替。 如果一个模块实例化一个 类,重新加载定义该类的模块不影响 实例的方法定义——它们继续使用 旧的类定义。派生类也是如此。

外部包

reimport - Reimport 目前支持 Python 2.4 到 2.7。

xreload- 这通过在临时命名空间中执行模块来工作,然后 修补类、方法和函数。这避免了 需要修补实例。新对象被复制到目标中 命名空间。

livecoding - 代码重新加载允许正在运行的应用程序更改其行为以响应其使用的 Python 脚本的更改。当库检测到 Python 脚本已被修改时,它会重新加载该脚本并用新重新加载的版本替换它之前可用的对象。作为一种工具,它允许程序员避免中断他们的工作流程和相应的失去焦点。它使他们能够保持心流状态。以前他们可能需要重新启动应用程序才能使更改的代码生效,而这些更改可以立即应用。

【讨论】:

【参考方案6】:

基本上reload 就像在 allyourcode 的 asnwer 中一样。但它不会改变已经实例化的对象或引用函数的底层代码。从他的回答延伸:

#Make a simple function that prints "version 1"
shell1$ echo 'def x(): print "version 1"' > mymodule.py

# Run the module
shell2$ python
>>> import mymodule
>>> mymodule.x()
version 1
>>> x = mymodule.x
>>> x()
version 1
>>> x is mymodule.x
True


# Change mymodule to print "version 2" (without exiting the python REPL)
shell2$ echo 'def x(): print "version 2"' > mymodule.py

# Back in that same python session
>>> reload(mymodule)
<module 'mymodule' from 'mymodule.pyc'>
>>> mymodule.x()
version 2
>>> x()
version 1
>>> x is mymodule.x
False

【讨论】:

【参考方案7】:

简答:

尝试使用reimport: a full featured reload for Python。

更长的答案:

看起来这个问题是在 reimport 发布之前提出/回答的,它自称是“Python 的全功能重载”:

此模块旨在成为 Python 重载功能的全功能替代品。它旨在使重新加载适用于运行时间较长的应用程序使用的 Python 插件和扩展。

Reimport 目前支持 Python 2.4 到 2.6。

就其本质而言,这不是一个完全可以解决的问题。该模块的目标是使最常见的更新工作正常。它还允许单个模块和包来协助该过程。概述页面上对所发生的情况进行了更详细的描述。

注意:虽然reimport 明确支持 Python 2.4 到 2.6,但我一直在 2.7 上尝试它,它似乎工作得很好。

【讨论】:

很好的发现。当您进行小的代码更改时,对于解释器中的简单情况似乎效果很好,这就是我真正想要的......【参考方案8】:

不确定这是否能完成所有预期的事情,但您可以这样做:

>>> del mymodule
>>> import mymodule

【讨论】:

【参考方案9】:
import sys
del sys.modules['module_name']

【讨论】:

impimportlib 解决方案对我不起作用。这做到了。我的情况是在一个 jupyter 笔记本中,我需要保存一个 keras 模型,但忘记事先运行 pip install h5py。在保存的时候,它抛出了一个异常save_model requires h5py。在此之前,并使用从keras.models 导入的save_model(而不是model.save(...) 函数起作用【参考方案10】:

请参阅此处,了解如何不重新加载依赖模块以及可能产生的影响:

http://pyunit.sourceforge.net/notes/reloading.html

pyunit 解决它的方法是通过覆盖 __import__ 来跟踪依赖模块,然后从 sys.modules 中删除每个模块并重新导入。不过,他们可能只是重新加载它们。

【讨论】:

稍微提炼一下——对我来说,简单的输入“reload()”在测试之间有效。简单地使用“del module; import module”是行不通的。【参考方案11】:

蜻蜓的回答对我有用(python 3.4.3)。

import sys
del sys.modules['module_name']

这是一个较低级别的解决方案:

exec(open("MyClass.py").read(), globals())

【讨论】:

这不会完全按照要求工作,因为名称空间将更改为全局。对不起。

以上是关于如何在 Python 解释器中重新导入更新的包? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

如何告诉 Python 重新导入我的脚本? [复制]

python如何导入不同目录下的包

如何从虚拟环境(virtualenv)启动 python Idle

修改 Python 模块的常见做法

Python:导入包含的包

python3模块和相关