如何在 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
被弃用,取而代之的是importlib
,reload
被添加到后者。面向 3 或更高版本时,请在调用reload
时引用相应的模块或将其导入。
外卖:
Python3 >= 3.4:importlib.reload(packagename)
Python3 imp.reload(packagename)
Python2:在下面继续
使用reload
内置函数:
https://docs.python.org/2/library/functions.html#reload
当
重新编译 Python 模块的代码并重新执行模块级代码,定义一组新的对象,这些对象绑定到模块字典中的名称。扩展模块的init函数不会被第二次调用。 与 Python 中的所有其他对象一样,旧对象仅在其引用计数降至零后才会被回收。 模块命名空间中的名称已更新,以指向任何新的或更改的对象。 对旧对象的其他引用(例如模块外部的名称)不会重新绑定以引用新对象,如果需要,必须在它们出现的每个命名空间中进行更新。reload(module)
被执行时:
例子:
# 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
已被弃用,取而代之的是 importlib
:importlib.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']
【讨论】:
imp
和 importlib
解决方案对我不起作用。这做到了。我的情况是在一个 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(蜻蜓的回答对我有用(python 3.4.3)。
import sys
del sys.modules['module_name']
这是一个较低级别的解决方案:
exec(open("MyClass.py").read(), globals())
【讨论】:
这不会完全按照要求工作,因为名称空间将更改为全局。对不起。以上是关于如何在 Python 解释器中重新导入更新的包? [复制]的主要内容,如果未能解决你的问题,请参考以下文章