9

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

怎么做?

更新:所以..这是我,问题作者,问题发布日期后 8 年。我不知道为什么我会尝试做那样的事情。

如果您阅读本文,请尝试使用适当的配置管理技术(大部分时间由您的框架提供)。

# ==================================
# 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
4

7 回答 7

3

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

1. 全局变量

spam = 100

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

这是行不通的。由于 Python 闭包的工作方式,您的spam = value行将在您的函数中创建一个新的局部变量,然后不会被使用。要正确更改 global 的值,您必须使用关键字,例如:spamset_spamspamglobal

spam = 100

def set_spam(value):
    global spam
    spam = value

2.“从自己”重新加载模块

据我所知,没有办法真正做到这一点,你也不应该这样做。您已import编辑的任何模块都是从其他模块调用的,一直到__main__. 您只需从该调用模块刷新它。是的,您可以尝试自行导入模块(尽管可能存在无限循环问题,如 mgilson 所述),但即便如此(使用名为“foo”的示例),如果您让它自行导入,您只需have foo.foo,并且做类似的事情foo.reload(foo)(如果这甚至是有效的)只会重新加载 sub- foo,而不是 base 。

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

通过对您尝试做什么的更多解释,我们可以帮助您重组代码以使其更好地工作。

于 2012-12-10T17:02:02.203 回答
2

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

import imp

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

print("loaded")

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

ps 我想每个人都认为这是一个坏主意:他们可能是对的,但是如果您正在交互式地开发一个模块,也许它会让事情变得更方便。在将代码分发给其他人之前将其取出,否则他们可能会感到困惑。

于 2013-05-26T18:25:07.133 回答
2

这里

import sys

reload(sys.modules[__name__])

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

于 2018-03-31T01:18:53.907 回答
1

我看不出你怎么能干净地做到这一点而不会陷入无限循环。也许有一个功能会更好reset

def reset():
    global spam
    spam = 100

请注意,这个设计对我来说仍然有点时髦。从长远来看,似乎更好的数据封装可能会对您有很大帮助——也许是这样的:

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

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

于 2012-12-10T16:32:40.410 回答
1

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

我的模块.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)')

主文件

import mymodule

mymodule.var = 'changed'
mymodule.refresh()
  # -> reloaded 1 times(s)
print(mymodule.var)
  # -> 0
mymodule.refresh()
  # -> reloaded 2 times(s)
于 2020-04-22T23:15:19.987 回答
0

This operation doesn't make sens at all. From Python documentation:

reload(module): Reload a previously imported module. The argument must be a module object, so it must have been successfully imported before.

So, reload make sens only from context of other module which performed import previously.

于 2012-12-10T16:40:14.697 回答
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
于 2021-04-28T23:23:57.343 回答