Dynamically loading instance method during object instantiation
Question: I want to be able to dynamically load instance methods during object
instantiation. According to my design, the default behaviour is coded in the
base class. However, if certain conditions are met during object
instatination, I dynamically change this behaviour with another piece of code.
This is how I do it:

The default behaviour is coded in `first.py`:

    
    
    class First(object):
        def __init__(self, p):
            p = str(p)
            #The decision whether or not to perform default action is done
            #in the following try/except block. In reality this block 
            #is more complicated
            #and more checks are performed in order to assure proper work
            try: 
                strImport = "__import__('module%s')"%p
                e = eval(strImport, {}, {})
                if not hasattr(e, p):
                    raise ImportError()
            except ImportError:
                e = None #default behaviour
            if e is not None:
                self.act = getattr(e, p)(p).act #special behaviour
            self.p = p
    
        def act(self):
            print 'Default behaviour'
    
    
    import cPickle as pickle
    
    
    
    if __name__ == '__main__':
        print 'first'
        first = First('f')
        first.act()
        pickle.dump(first, open('first.dump', 'w'))
    
        print 'third'
        third = First('Third')
        third.act()
        pickle.dump(third, open('third.dump', 'w'))
    

In the code above, both `first` and `third` perform default action. I can
change the behaviour of `third` by adding a file `moduleThird.py` as follows:

    
    
    from temp import First
    class Third(First):
        def __init__(self, p):
            p = 'Third *** %p'
            print 'third init'
            super(self.__class__, self).__init__(p)
    
    
        def act(self):
            super(self.__class__, self).act()
            print 'Third acted'
    

After this file has been added, `third` changes its behaviour. However I'm not
unable to pickle the resulting object due to the following error:

    
    
    Traceback (most recent call last):
      File "C:\temp\temp.py", line 35, in <module>
        pickle.dump(fff, open('fff.dump', 'w'))
      File "C:\Python26\lib\copy_reg.py", line 70, in _reduce_ex
        raise TypeError, "can't pickle %s objects" % base.__name__
    TypeError: can't pickle instancemethod objects
    

It is clear that the dynamically loading method `Third.act` is causing the
problems with pickle. How do I need to change my approach in order to get
pickable objects (and more elegant code too)?

Is there a better way to acheive my goal?


Answer: If you change your code as follows then it should work:

    
    
    class First(object):
        def __init__(self, p):
            p = str(p)
            #The decision whether or not to perform default action is done
            #in the following try/except block. In reality this block 
            #is more complicated
            #and more checks are performed in order to assure proper work
            try: 
                strImport = "__import__('module%s')"%p
                print strImport
                e = eval(strImport, {}, {})
                if not hasattr(e, p):
                    raise ImportError()
    
                self.override_obj = getattr(e, p)(p)
            except ImportError:
                e = None #default behaviour
                self.override_obj = None
    
            self.p = p
    
        def act(self):
            if self.override_obj:
                return self.override_obj.act()
            else:
                print 'Default behaviour'
    

