#1
  1. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Nov 2012
    Posts
    11
    Rep Power
    0

    Re-instantiate shelved objects to access them with same syntax as pre-shelving?


    Hello,

    I have a script which does the following:

    1. Parses a long csv file and creates several objects of various classes
    2. Opens a GUI displaying these objects with various widgets for changing values
    3. Serializes all the objects into a shelve data file.

    I would like to be able to load the saved session and start at step 2 (using the shelved objects instead of re-parsing the csv file every time).

    My GUI accesses all of the objects this way:

    object.property

    but when shelved, the objects are stored something like this:

    my_shelve_db['LIST_OF_OBJECTS_CLASS1']
    my_shelve_db['LIST_OF_OBJECTS_CLASS2']

    Should I just do a for-loop through each list of objects and re-initialize them all? Is there a way to do this that is flexible (so that if I add properties in the future, I don't have to change the parsing code in two places -- the original csv parsing AND the shelve load parsing.

    Or is there a more elegant way to restore shelved instances to their original instantiated state? (The objects are created dynamically through parsing the text file, so they don't have hard-coded names).

    Thanks!
  2. #2
  3. Contributing User
    Devshed Demi-God (4500 - 4999 posts)

    Join Date
    Aug 2011
    Posts
    4,843
    Rep Power
    480

    Confused


    Shelves have the same interface as dictionaries. To store an object you'd write
    shelf['key'] = obj
    where as you say this without an assignment:
    but when shelved, the objects are stored something like this:

    my_shelve_db['LIST_OF_OBJECTS_CLASS1']
    Please provide an example of the problem using class c and no gui.

    Code:
    import shelve
    
    class c:
    	pass
    
    o = c()
    o.attribute = 'changed value'
    
    shelf = shelve.open('/tmp/shelf')
    shelf['o'] = o
    shelf.close()
    
    del o
    
    shelf = shelve.open('/tmp/shelf')
    print('shelf.keys()):',shelf.keys())
    o = shelf['o']
    shelf.close()
    
    print('dir(o):',dir(o))
    print('o.attribute:',o.attribute)
    [code]Code tags[/code] are essential for python code and Makefiles!
  4. #3
  5. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Nov 2012
    Posts
    11
    Rep Power
    0
    I may have answered my own question while trying to put together a sample script for you.

    My objects are created dynamically through a parsing loop, so they don't have their own individual names (e.g. 'o' in your example) to call easily. So I couldn't assign the values as you recommended ( o = shelf['o'] ) without knowing every object ahead of time.

    In my script, any time I edit an object, I do the following:

    1. Iterate through a list of objects in that class (MyClass.ObjectList) using a classmethod (myobject = MyClass.FindByName(name)
    2. Change the value that object using the object's method (e.g. myobject.ChangeValue(attribute, value)

    It turns out that all I had to do was shelve MyClass.ObjectList (in addition to shelving the individual objects). Then upon loading the shelved data I could assign MyClass.ObjectList = shelf['myclass_objectlist']. I didn't think this would work without somehow shelving the methods as well. But it appears that as long as the class definitions are in the script, its methods will operate on shelved objects even if the objects were not instantiated in the current session. (At least this seems to be the case based on my experimenting -- correct me if I'm wrong).

    Here is my sample code which seems to work. But I am a relative newbie to Python and OOP, so if you see any holes, potential issues, or something for which a better solution exists, I'd appreciate any advice:

    Code:
    ### PYTHON 3 Grammar
    
    import shelve
    
    class c(object):
        list_of_things = []
        names_list = []
        
        def __init__(self, name):
            self.name = name
            self.colorlist = []
            self.data = {}
            c.list_of_things.append(self)
            c.names_list.append(self.name)
            print('Initialized Thing:',self.name, self)
            
        def ChangeValue(self, color, newvalue):
            print('Original Value:',self.name, color, self.data[color])
            self.data[color] = newvalue
            print('Value changed:',self.name, color, self.data[color])
        
            
        @classmethod
        def FindThingByName(self, name_to_find):
            for thing in c.list_of_things:
                if thing.name == name_to_find:
                    return thing        
            
    ################### SIMPLIFIED SIMULATION OF PARSING MY CSV  FILE###
    Contents_ParseFile = \
    'Thing1,Blue,Schamobble\n\
    Thing1,Green,Plumdiffoo\n\
    Thing2,Yellow,Kwallabooble\n\
    Thing2,Blue,Shoremilk\n\
    Thing3,Purple,Stimkinzikle'
    
    lines = Contents_ParseFile.split('\n')
    
    for line in lines:
        splitline = line.split(',')
        name = splitline[0]
        color = splitline[1]
        nonsense = splitline[2]
    
        if name not in c.names_list:
            ####### INITIALIZATION OF OBJECT CLASS c
            thisthing = c(name)
            ######## OBJECTS HAVE NO PERMANENT VARIABLE NAMES
            ######## BECAUSE THEY ARE GENERATED DYNAMICALLY
            ######## FROM A CSV FILE WITH VARYING CONTENT
        else:
            ######## (If thing already exists, do not initialize a new object)
            thisthing = c.FindThingByName(name)
            
        thisthing.colorlist.append(color)
        thisthing.data[color] = nonsense
            
        print(' => Updated value for',thisthing.name, color, nonsense)
    #######################################################    
    
    
    def SimulateValueChange(name, color, newvalue):
        '''Simple simulation of a value change that might occur in the GUI'''
        mything = c.FindThingByName(name)
        mything.ChangeValue(color,newvalue)
    
    def SaveSession():    
        shelf = shelve.open('shelfdata')
        
        # Shelve the list of things
        shelf['thinglist'] = c.list_of_things   
        
        # Shelve the entire object using its unique name as the key:
        for thing in c.list_of_things: 
            shelf[thing.name] = thing  
        print('\n++++++++++++++++++++++\nSession has been saved\n++++++++++++++++++++++')
        shelf.close()
        
    print('\n+++ Simulating a simple edit that might occur in the GUI:')
    SimulateValueChange('Thing1','Blue','FoShizzle')
    
    SaveSession()
    
    #### Deleting /resetting data #########
    for thing in c.list_of_things:
        # resetting attributes for reasons in side question below
        thing.name = '' 
        thing.colorlist = []
        thing.data = {}
        del(thing)  
        ## side question - even after deleting, these objects still 
        ## turn up when invoking c.FindByName class method???
        ## which is why I reset all the properties to blank values for
        ## the purpose of testing shelve
    c.list_of_things = []
    c.names_list = []
    #######################################
    
    shelf = shelve.open('shelfdata')
    print('\n+++ Accessing value through shelf:',shelf['Thing1'].data['Blue'])
    
    ######### IT TURNS OUT THIS IS ALL I NEEDED TO ADD TO MY CODE ######
    c.list_of_things = shelf['thinglist']
    ####################################################################
    
    print('\n\n+++ Changing Value after opening shelf \n\
    +++ (using same function as I used to access objects before shelving) +++\n')
    
    try:
        SimulateValueChange('Thing1','Blue','ThisIsMyNewValue')
    except AttributeError:
        print('\nError Accessing Shelved Object ')
        
    shelf.close()
    Thanks!

IMN logo majestic logo threadwatch logo seochat tools logo