如何从自身重新加载python模块?
我有一个包含很多变量的python模块。这些变量由许多其他模块使用和更改。当这个模块发生时,我想从它自身重新加载它(用于刷新) 怎么做 upd:so。。这是我,问题作者,问题发表8年后。我不知道为什么我会尝试做那样的事 如果您阅读了本文,请尝试使用适当的配置管理技术(大部分时间由您的框架提供)如何从自身重新加载python模块?,python,Python,我有一个包含很多变量的python模块。这些变量由许多其他模块使用和更改。当这个模块发生时,我想从它自身重新加载它(用于刷新) 怎么做 upd:so。。这是我,问题作者,问题发表8年后。我不知道为什么我会尝试做那样的事 如果您阅读了本文,请尝试使用适当的配置管理技术(大部分时间由您的框架提供) 我不明白你怎么能干净利落地做到这一点而不陷入无限循环。也许有一个重置功能会更好 def reset(): global spam spam = 100 注意,这个设计对我来说仍然有点时髦
我不明白你怎么能干净利落地做到这一点而不陷入无限循环。也许有一个
重置
功能会更好
def reset():
global spam
spam = 100
注意,这个设计对我来说仍然有点时髦。从长远来看,更好的数据封装可能会对您有很大帮助——可能类似于:
def new_namespace():
return {'spam':100}
然后,您的其他每个函数都可以接受名称空间字典作为参数,而不是依赖
foo
名称空间。此操作根本没有意义。发件人:
重新加载(模块):重新加载以前导入的模块。参数必须是模块对象,因此它必须在导入之前已成功导入
因此,
reload
仅从先前执行import
的其他模块的上下文中进行传感 您试图实现的目标有很多问题,除非您有意设置一个自我修改的代码系统,而您看起来并不是这样
1.全局变量
这是行不通的。由于Python闭包的工作方式,您的spam=value
行将在set\u spam
函数中创建一个新的局部变量spam
,该变量将不会被使用。要正确更改全局垃圾邮件
的值,必须使用全局
关键字,如下所示:
spam = 100
def set_spam(value):
global spam
spam = value
2.“从自身”重新加载模块
据我所知,实际上没有办法做到这一点,你也不需要这样做。导入的任何模块都会从其他模块调用,一直调用到\uuuuuu main\uuuu
。您只需从调用模块刷新它。是的,您可以尝试自导入模块(尽管可能存在无限循环问题,正如mgilson所提到的),但即使如此(使用一个名为“foo”的示例),如果您让它自己导入,您也只需要foo.foo
,并执行类似foo.reload(foo)
(如果这是有效的)只需重新加载子文件,而不是基本文件
3.完全重新加载foo.py
请注意,在该代码的顶部,您是如何将100分配给垃圾邮件的。每次导入模块时,您都将再次执行该操作。因此,即使您已经在导入的foo
代码中更改了spam
的值,当您重新加载模块时,您实际上正在破坏您刚才所做的更改。例如:
>>> import foo
>>> foo.spam
100
>>> foo.spam = 9
>>> foo.spam
9
>>> reload(foo)
>>> foo.spam
100
因此,如果要保留对foo
中变量所做的更改,则应而不是重新加载模块。此外,您甚至不需要使用set\u spam
函数来更改spam
,您可以像我一样直接设置它
4.尝试在其他模块中使用此“已更改”模块值
最后,如果我正确理解了你的意图,那是行不通的。这在很大程度上是因为我在第3部分中提到过,每次加载foo
,spam=100
行将重置spam
的值。同样,如果您将foo
模块导入其他两个不同的模块中,当每个模块导入它时,它们都将以spam=100
开始,完全独立于其他模块对foo.spam
所做的操作。例如,如果bar1.py
和bar2.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
通过对您试图执行的操作进行更多解释,我们可以帮助您重新构造代码,使其工作得更好。在Python 2.6.2中,这很简单。假设您的模块名为“t”,定义如下:
import imp
def reload():
name="t"
imp.load_module(name,*imp.find_module(name))
print("loaded")
加载此模块后,添加另一个成员并执行t.reload()
p、 我想每个人都认为这是个坏主意:他们可能是对的,但如果你以交互方式开发一个模块,可能会使事情变得更方便。在您将代码分发给其他人之前,请将其取出,否则他们可能会感到困惑。此处
import sys
reload(sys.modules[__name__])
注意,这不适用于main
模块,但适用于任何其他模块。您还可以计算模块重新加载的次数!:
mymodule.py
main.py
这里是前一个答案的另一个版本,只有当计数器不存在时才初始化它。在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)')
这听起来是个相当糟糕的主意…@Wooble,好吧,那么。。你推荐什么?将所有这些变量包装为Singleton类?在您的特定情况下,我认为您只需要将全局垃圾邮件
放在set_spam
函数的顶部,但我并不完全清楚为什么您认为重新加载可以将值保持在200。如果有的话,它会在设置后立即将其重置为100,这没有任何意义。@Wooble比依赖用户来重新加载(模块)
要好得多。好吧,它是在系统模块
中全局设置的,所以它不像听起来那么荒谬。显然,该模块不应该从全局范围重新加载,而应该从另一个模块调用的函数重新加载!No go:->ImportError:无法重新初始化内部模块main良好捕获,但它可以与除main
之外的模块一起工作。但是,如果您在函数内部,则可以执行较旧版本的函数,但您可以定义包装器-一个带有重载函数调用的主函数,一个被包装的函数被更新,它将被称为af
import imp
def reload():
name="t"
imp.load_module(name,*imp.find_module(name))
print("loaded")
import sys
reload(sys.modules[__name__])
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)
# 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