python - 重新加载/重新导入使用 from * import * 导入的文件/类

标签 python linux python-3.x python-import

好吧,正如标题所说,我有一组导入,所有导入一个类,都在与运行它的脚本相同的文件夹中:

from lvl import lvl
from get import get
from image import image
from video import vid
from video import MLStripper
from system import system
from setting import setting
from listsearch import lists

python3 没有 reload iirc 但有 imp.reload() 但它似乎不起作用,

它只是抛出一个错误,说它不是模块(它是一个类,所以它不起作用)

在导入的那些类中的每一个小编辑之后,我都需要重新启动脚本

有没有办法重新加载/重新导入类来显示编辑的效果而无需启动脚本或重写大部分脚本以便 imp.reload() 工作?

python3,linux(但如果它也适用于窗口则更喜欢)

编辑1:

示例:如果我使用:
import system
system.system.temp()

它返回:
65°C

如果我将其更改为显示°F并使用 imp.reload 重新加载
imp.reload(system)
system.system.temp()

它返回:
149°F

所以,它可以工作,但如果我使用
import system as _system
from system import system
system.temp()

它返回:
65°C

然后我将其更改为显示°F并使用 imp.reload 重新加载
imp.reload(_system)
from system import system
system.temp()

它仍然返回
65°C

但是,如果我这样称呼它:
_system.system.temp()

它返回
149°F

我知道为什么会这样,但它是因为它发生在一个while循环中?

编辑2:

文件名:system.py:

在更改测试之前:
class system:
  def temp():
    temperature = open("/sys/class/thermal/thermal_zone0/temp","r").read()
    temperature = temperature[:2]
    return(temperature+"°C")

更改测试后:
class system:
  def temp():
    temperature = open("/sys/class/thermal/thermal_zone0/temp","r").read()
    temperature = temperature[:2]
    temperature = str(9.0 / 5.0 * int(temperature) + 32).split(".")[0]
    return(temperature+"°C")

最佳答案

你只能 reload 一个模块:

The argument must be a module object, so it must have been successfully imported before.



在您的情况下,您没有对模块对象的任何引用。您将不得不 import它,即使你不想将它用于其他任何事情,只是为了调用 reload之后。

此外,在 reload 之后,你已经重新- import名字:

Other references to the old objects (such as names external to the module) are not rebound to refer to the new objects and must be updated in each namespace where they occur if that is desired.



当你这样做 from foo import bar , 那 bar是“模块外部的名称”,因此您必须明确地重新绑定(bind)它。

如果您考虑一下,它必须以这种方式工作。没办法reload可以枚举其定义依赖于以前版本的模块的所有对象来更新它们。即使可以,也可能有无限循环。如果新版本甚至没有为旧版本中的类定义会发生什么?或者如果类是动态定义的?

换个角度看,from foo import barimport foo; bar = foo.bar 非常相似. bar是您命名空间中的名称,而不是 foo的命名空间,所以 reload(foo)不会碰它;你需要复制新的foo.bar再次。

解决所有这些问题的简单方法是重复所有 from foo import bar reload 之后的行.

对于简单的情况:
import video
from video import MLStripper

# ... later

imp.reload(video)
from video import MLStripper

但是,您的大多数示例都有明显的命名冲突:一旦您 from video import video ,你不能再reload(video) .因此,您需要另一个引用 video模块对象。

Python 为您保留了一个,您可以使用它:
imp.reload(sys.modules['video'])
from video import MLStripper

或者,您也可以使用 as子句,或者只是一个 =分配,给它任何你想要的名字。
import video as _video
from video import video

# ... later

imp.reload(_video)
from video import video

从您的评论和编辑的问题来看,听起来您还有一个问题。让我们使用一个简单的非碰撞案例来讨论它。

我相信你实际上正在做这样的事情:
import video
from video import MLStripper

stripper = MLStripper('foo")

# ... later

imp.reload(video)
from video import MLStripper

第一行将成功重新加载 video模块,第二个将复制它的MLStripper类到你的全局变量中,所以任何新的MLStripper您创建的实例将属于新类型。

但这不会影响任何现有的 MLStripper实例,例如 stripper .

就像 MLStripper是,stripper是那些“模块外部的名称”之一。但实际上情况更糟。为了调整它,reload如果新版本的代码在创建时就已经生效,则必须弄清楚它的状态是什么。应该很明显,这是一个无法解决的问题。

如果您知道要修补的实例,则可以像处理类一样有效地处理它们:只需再次创建它们:
imp.reload(video)
from video import MLStripper
stripper = MLStripper('foo")

如果这还不够好,那么您可能想要三种 hacky 可能性:
  • 将方法、属性等Monkeypatch 到实例及其__class__ 中(西)。
  • 修补实例的 __class__属性直接,所以从类继承的任何东西现在都将从新类继承。
  • 使用 pickle 序列化实例在 reload 之前,然后反序列化。

  • 对于非常简单的情况,所有这三个都可以工作。对于更复杂的情况,您必须了解自己在做什么。

    请注意,您可以将很多这些东西包装在一个函数中,但是您必须了解局部变量和全局变量的工作方式(以及导入和重新加载的工作方式),否则您最终会感到困惑。

    一个更简单的解决方案是只创建“转储所有状态”和“加载所有状态”功能。然后,您可以转储所有内容、退出、重新启动和恢复。 Python 教程和 ipython 文档都描述了几种不同的方法来代替使用 reload ;可能值得回去重新阅读这些内容。

    关于python - 重新加载/重新导入使用 from * import * 导入的文件/类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17178995/

    相关文章:

    Python HTTP 服务器可用于多个请求

    python - 在 jupyter 笔记本单元格上加载 Markdown 文件

    python - 带有 spacy 的自定义 POS 标记

    linux - 将文件夹系统中的所有 .docx 转换为 .odt,然后删除所有 .docx 文件

    Linux:桥上的端口隔离以正确使用 OLSR

    python-3.x - 如何在图像中找到对象的方向?

    python - Django 中的空白 URL 模式

    node.js - NodeJS fs.unlink() 不释放文件句柄

    python - 如何使用 AST python 模块从中缀转换为后缀/前缀?

    python - 如何使用 Python 在 Selenium 中测试 Alert/Popup