Reputation: 5662
I have a python module with a lot of variables. These variables are used and changed by many other modules. And I want to reload this module from itself when it happens (for refresh).
How to do that?
upd: so.. this is me, question author, 8 years after the question publication date. I have zero idea why I would try to do something like that then.
If you read this, please attempt to use proper configuration management techniques (most of the time supplied by your framework) instead.
# ==================================
# 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
Upvotes: 11
Views: 9410
Reputation: 2707
Here is another version of the previous answer with the counter only initialized if it does not exist. Tested on 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
Upvotes: 0
Reputation: 339
You also can count the times the module was reloaded!:
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)
Upvotes: 2
Reputation: 27793
Here
import sys
reload(sys.modules[__name__])
NB, this does not work with the main
module but with any other module.
Upvotes: 2
Reputation: 17042
There are a number of problems with what you're trying to achieve, unless you're deliberately setting up a self-modifying code system, which it doesn't look like you are.
spam = 100
def set_spam(value):
spam = value
foo = reload(foo) #reload module from itself
This is not going to work. Because of how Python closures work, your spam = value
line is going to create a new local variable spam
within your set_spam
function, which then won't get used. To properly change the value of the global spam
, you have to use the global
keyword, as such:
spam = 100
def set_spam(value):
global spam
spam = value
As far as I know, there's no way to actually do this, nor should you need to. Any module you've import
-ed is called from some other module, all the way up to __main__
. You would simply refresh it from that calling module. Yes, you could attempt to self-import a module (though there might be infinite loop issues, as mentioned by mgilson), but even then (using an example named "foo"), if you had it import itself, you'd just have foo.foo
, and doing something like foo.reload(foo)
(if that's even valid) would simply reload the sub-foo
, not the base one.
foo.py
at all# ==================================
# foo.py
spam = 100
def set_spam(value):
global spam
spam = value
Note how at the top of this code, you're assigning 100 to spam
. Every time you import the module, you'll be doing that again. So, even if you've already changed the value of spam
in the code that's imported foo
, when you reload the module, you'll actually be destroying the change you just made. Example:
>>> import foo
>>> foo.spam
100
>>> foo.spam = 9
>>> foo.spam
9
>>> reload(foo)
>>> foo.spam
100
So if you want to keep the changes you've made to the variable in foo
, you should not reload the module. Furthermore, you really don't even need to use a set_spam
function to change spam
, you can just set it directly, as I did.
Finally, if I understand correctly what you're trying to do, that's not going to work. This is in large part because of something I mentioned in part 3, wherein every time you load foo
, the spam=100
line is going to reset the value of spam
. In the same way, if you import the foo
module in two different other modules, when each one imports it, they're each going to start out with spam = 100
, completely independently of what the other module does with foo.spam
. Example, if both bar1.py
and bar2.py
contain the line 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
With more explanation about what you're trying to do, we could help you restructure your code to make it work better.
Upvotes: 3
Reputation: 11728
In Python 2.6.2 it is simple. Assume your module is named "t" and is defined as follows:
import imp
def reload():
name="t"
imp.load_module(name,*imp.find_module(name))
print("loaded")
After you have loaded this module add another member it and execute t.reload().
p.s. I guess everybody thinks this is a bad idea: they're probably right, but if you're interactively developing a module maybe it makes things more convenient. Just take it out before you distribute your code to others or they might get confused.
Upvotes: 3
Reputation: 6234
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.
Upvotes: 0
Reputation: 309831
I don't see how you could do this cleanly without getting caught in an infinite loop. Maybe it would be better to have a reset
function?
def reset():
global spam
spam = 100
Note that this design still seems a little funky to me. It seems like better data encapsulation would probably help you a lot in the long run -- Perhaps something like:
def new_namespace():
return {'spam':100}
Then each of your other functions could accept a namespace dictionary as an argument rather than relying on the foo
namespace.
Upvotes: 1