如何从自身重新加载python模块?

时间:2012-12-10 16:28:09

标签: python

我有一个包含很多变量的python模块。许多其他模块使用和更改这些变量。我想在它发生时重新加载这个模块(刷新)。

怎么做?

# ==================================
# foo.py

spam = 100

def set_spam(value):
    spam = value
    foo = reload(foo) # reload module from itself

# ==================================
# bar.py

import foo
print foo.spam # I expect 100
# assume that value changes here from some another modules (for example, from eggs.py, apple.py and fruit.py)
foo.set_spam(200)
print foo.spam # I expect 200

7 个答案:

答案 0 :(得分:3)

你想要实现的目标有很多问题,除非你故意设置一个自我修改的代码系统,它看起来不像你。

1。全局变量

spam = 100

def set_spam(value):
    spam = value
    foo = reload(foo) #reload module from itself

这不起作用。由于Python闭包的工作原理,您的spam = value行将在spam函数中创建一个新的本地变量set_spam,然后不会被使用。要正确更改全局spam的值,您必须使用global关键字,因此:

spam = 100

def set_spam(value):
    global spam
    spam = value

2。重新加载模块“从他们自己”

据我所知,实际上没有办法实现这一点,也不需要。您import - ed的任何模块都会从其他模块调用,一直到__main__。您只需从该调用模块刷新它。是的,你可以尝试自我导入一个模块(虽然可能存在无限循环问题,如mgilson所述),但即便如此(使用名为“foo”的例子),如果你有它导入本身,您只需要foo.foo,并执行类似foo.reload(foo)的操作(如果这甚至有效)只会重新加载子foo,而不是基础。{/ p>

3。重新加载foo.py

# ==================================
# foo.py

spam = 100

def set_spam(value):
    global spam
    spam = value

请注意,在此代码的顶部,您将100分配给spam每次导入模块时,您都会再次执行此操作。因此,即使您已经在导入的代码spam中更改了foo的值,当您重新加载模块时,您实际上也会破坏您刚才所做的更改。例如:

>>> import foo
>>> foo.spam
100
>>> foo.spam = 9
>>> foo.spam
9
>>> reload(foo)
>>> foo.spam
100

因此,如果您想保留对foo中的变量所做的更改,则应重新加载模块。此外,您甚至不需要使用set_spam函数来更改spam,您可以像我一样直接设置它。

4。尝试在其他模块中使用此“已更改”模块值

最后,如果我理解你正在尝试做什么,那就不行了。这在很大程度上是因为我在第3部分中提到的内容,其中每次加载foo时,spam=100行都会重置spam的值。同样,如果您在两个不同的其他模块中导入foo模块,当每个模块都导入它时,它们将分别从spam = 100开始,完全独立于其他模块的模块。与foo.spam。例如,如果bar1.pybar2.py都包含行import foo

>>> import bar1, bar2
>>> bar1.foo.spam
100
>>> bar2.foo.spam
100
>>> bar1.foo.spam = 200
>>> bar1.foo.spam
200
>>> bar2.foo.spam
100

有关您正在尝试执行的操作的更多说明,我们可以帮助您重新构建代码,使其更好地运行。

答案 1 :(得分:2)

在Python 2.6.2中,它很简单。假设您的模块名为“t”,定义如下:

import imp

def reload():
    name="t"
    imp.load_module(name,*imp.find_module(name))

print("loaded")

加载此模块后,添加另一个成员并执行t.reload()。

P.S。我想每个人都认为这是一个坏主意:它们可能是正确的,但如果你是交互式地开发模块,那么它可能会让事情变得更加方便。只需在将代码分发给其他人之前将其删除,否则他们可能会感到困惑。

答案 2 :(得分:1)

我不知道如何干净利落地做到这一点而不会陷入无限循环。也许最好有一个reset函数?

def reset():
    global spam
    spam = 100

请注意,这个设计对我来说似乎有点时髦。从长远来看,似乎更好的数据封装可能对你有很大的帮助 - 或许类似于:

def new_namespace():
    return {'spam':100}

然后,您的每个其他函数都可以接受命名空间字典作为参数,而不是依赖于foo命名空间。

答案 3 :(得分:1)

此操作根本不会产生任何感觉。来自Python documentation

  

重新加载(模块):重新加载以前导入的模块。参数必须是模块对象,因此必须先成功导入。

因此,reload仅使用先前执行import的其他模块的上下文来表示感知。

答案 4 :(得分:1)

下面

import sys

reload(sys.modules[__name__])

注意,这不适用于main模块,但适用于任何其他模块。

答案 5 :(得分:1)

您还可以计算模块重新加载的次数!:

mymodule.py

import importlib
import sys

count = 0
var = 0

def refresh():
    global count
    c = count
    importlib.reload(sys.modules[__name__])
    count = c + 1
    print (f'reloaded {count} time(s)')

main.py

import mymodule

mymodule.var = 'changed'
mymodule.refresh()
  # -> reloaded 1 times(s)
print(mymodule.var)
  # -> 0
mymodule.refresh()
  # -> reloaded 2 times(s)

答案 6 :(得分:0)

这是先前答案的另一个版本,计数器仅在不存在时才初始化。在 python 3.8.6 上测试

# mod.py
import importlib, sys

a=0

def reload():
  
    importlib.reload(sys.modules[__name__])
    global i
    try:
        i += 1
    except:
        i = 1
    print(f'reloaded {i} time(s)')

# main.py
import mod

mod.a = 10
print (mod.a) # -> 10
mod.reload() # -> reloaded 1 time
print (mod.a) # -> 0
mod.reload() # -> reloaded 2 times