-3

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

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")
4

2 回答 2

3

你只能reload一个模块:

参数必须是一个模块对象,所以它必须之前已经成功导入。

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

此外,在 之后reload,您可以重新import命名:

对旧对象的其他引用(例如模块外部的名称)不会重新绑定以引用新对象,并且如果需要,必须在它们出现的每个命名空间中进行更新。

当你这样做时from foo import bar,这bar是一个“模块外部的名称”,所以你必须明确地重新绑定它。

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

换个角度看,from foo import barimport foo; bar = foo.bar. bar是你命名空间中的名字,而不是foo's 命名空间,所以reload(foo)不会碰它;您需要重新复制新foo.bar的。

解决所有这些问题的简单方法是from foo import barreload.


对于简单的情况:

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用before序列化实例,reload然后在之后反序列化。

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


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

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

于 2013-06-18T21:22:36.430 回答
2

通过 访问模块sys.modules,重新加载模块,然后重新分配导入的名称:

imp.reload(sys.modules['lvl'])
from lvl import lvl

imp.reload(sys.modules['get'])
from get import get

等等

所有from something import name语法都是导入something然后绑定name到同一个对象something.name引用。

通过使用sys.modules,您不必再次显式导入模块,并且可以在重新加载后达到重新绑定对象的新定义。

于 2013-06-18T21:18:23.947 回答