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

时间:2013-06-18 21:10:31

标签: 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没有重载iirc但是有imp.reload()但它似乎不起作用,

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

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

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

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

EDIT1:

示例:如果我使用:

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

idk为什么会这样但是它会导致它在while循环中发生?

EDIT2:

文件名: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")

2 个答案:

答案 0 :(得分:2)

你只能reload一个模块:

  

参数必须是模块对象,因此必须先成功导入。

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

此外,在reload之后,您重新import名称:

  

对旧对象的其他引用(例如模块外部的名称)不会反弹以引用新对象,如果需要,必须在每个命名空间中进行更新。

执行from foo import bar时,bar是“模块外部的名称”,因此您必须明确重新绑定它。

如果您考虑一下,它以这种方式工作。 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__(es)中。
  • 直接修补实例'__class__属性,因此从类中继承的任何内容现在都将从新类继承。
  • pickle之前使用reload序列化实例,然后在之后反序列化。

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


请注意,您可以在函数中包含很多这些内容,但是您必须了解本地和全局变量的工作方式(以及导入和重新加载的工作方式),否则您最终会让自己感到困惑。

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

答案 1 :(得分:0)

通过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,您不必再次显式导入模块,并且可以在重新加载后到达对象的新定义以进行重新绑定。