views:

412

answers:

2

I'm trying to implement dynamic reloading objects in Python, that reflect code changes live.

Modules reloading is working, but I have to recreate every instance of the modules' classes for changes to become effective.

The problem is that objects data (objects __dict__ content) is lost during the process.

So I tried another approach:

def refresh(obj, memo=None):
    if memo is None:
        memo = {}
    d = id(obj)
    if d in memo:
        return
    memo[d] = None
    try:
        obj.__class__ = getattr(sys.modules[obj.__class__.__module__], 
                obj.__class__.__name__)
    except TypeError:
        return
    for item in obj.__dict__.itervalues():
        if isinstance(item, dict):
            for k, v in item.iteritems():
                refresh(k, memo)
                refresh(v, memo)
        elif isinstance(item, (list, tuple)):
            for v in item:
                refresh(v, memo)
        else:
            refresh(item, memo)

And surprisingly it works ! After calling refresh() on my objects, the new code becomes effective, without need to recreate them.

But I'm not sure if this is the correct way to traverse an object ? Is there a better way to traverse an object's components ?

+1  A: 

See this recipe in the Python Cookbook (or maybe even better its version in the "printed" one, which I believe you can actually read for free with google book search, or for sure on O'Reilly's "Safari" site using a free 1-week trial subscription -- I did a lot of editing on Hudson's original recipe to get the "printed book" version!).

Alex Martelli
This is very similar to the solution I adopted (some "top level" classes are wrapped and track their instances to allow reloading them). The problem is that I don't want to wrap all the classes in my package (or inherit from a reloading class as in your example), just the top level ones. This is why I need an object tree traversing function.
Luper Rouch
Alex Martelli
Ok then I just have to add more type tests in my iterations switch. It would be nice to have some kind of has_sequence_interface/has_mapping_interface() functions to test the way an object can be iterated.
Luper Rouch
A: 

For reloading Python code, I came up with this implementation a long time ago.

http://www.codexon.com/posts/a-better-python-reload

It's probably the fastest and cleanest way possible.

Unknown
Your code does not work with mine (raises a "AttributeError: __provides__" error, I think it does not play well with zope.interface). Besides I don't think it can reload instances within instances, which is what I'm trying to achieve.
Luper Rouch
It wasn't meant to interface with another reloader. As for reloading instances within instances, it doesn't need to since it changes the class instead of the instances. Methods called on instances will automatically be transferred to the new class.
Unknown
I disabled all my reload code when trying yours, just executing your reload() function on modules that had to be reloaded. Sorry I did not understand what it does, I will try to debug my problem when I have time.
Luper Rouch
@Luper, its ok don't worry about it. If you find a solution that works better for you, go with it.
Unknown