Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to reload python module from itself?

Tags:

python

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
like image 459
Bruno Gelb Avatar asked Dec 10 '12 16:12

Bruno Gelb


2 Answers

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.

1. Global variables

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

2. Reloading modules "from themselves"

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.

3. Reloading 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.

4. Trying to use this "changed" module value in other modules

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.

like image 108
jdotjdot Avatar answered Oct 23 '22 14:10

jdotjdot


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.

like image 2
tjb Avatar answered Oct 23 '22 14:10

tjb