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

如何从自身重新加载python模块?,python,Python,我有一个包含很多变量的python模块。这些变量由许多其他模块使用和更改。当这个模块发生时,我想从它自身重新加载它(用于刷新) 怎么做 upd:so。。这是我,问题作者,问题发表8年后。我不知道为什么我会尝试做那样的事 如果您阅读了本文,请尝试使用适当的配置管理技术(大部分时间由您的框架提供) 我不明白你怎么能干净利落地做到这一点而不陷入无限循环。也许有一个重置功能会更好 def reset(): global spam spam = 100 注意,这个设计对我来说仍然有点时髦

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

怎么做

upd:so。。这是我,问题作者,问题发表8年后。我不知道为什么我会尝试做那样的事

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


我不明白你怎么能干净利落地做到这一点而不陷入无限循环。也许有一个
重置
功能会更好

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