Dictionary type access to list of instances

Bengt Richter bokr at oz.net
Wed Feb 27 03:59:04 EST 2002


On Tue, 26 Feb 2002 09:44:33 +0200, "Grant Beasley" <gbeasley at tsa.ac.za> wrote:
[...]
>
>What I'm ultimately aiming for is a database-like view of a list of
>instances, so that I can use SQL commands to get instances. So in the
>analogy, a list of instances would be a table, with each instance a record,
>and each property a field.
>
>eg.
>class User:
>    def __init__(self, username, accesslevel):
>        self.username = username
>        self.accesslevel = accesslevel
>
>list = [User('Bob', 1), User('Jim', 2), User('Pete', 2)]
>
>Then using my imaginary function ListSQL:
>
>ListSQL("select * from list where accesslevel = 2")
>would return a list consisting of the Jim and Pete instances.
>
>or ListSQL("select username, accesslevel from list where accesslevel = 2")
>would return [('Jim', 2), ('Pete',2)] - i.e. a List of tuples.
>
>Is this an interesting / useful idea? Has it been done before? Any comments?
>
Well, it got me to try out properties and weak references and
modifying a class variable before use of the class ;-).

I'm on thin ice here, so comments from someone who's been using
these features a while would be welcome. ;-)

Below is an interaction from my categorizer.py (see listing at end):
In this case I am just using name strings as objects, but they
could be any objects. The Categorizer class wraps objects you
give to it in a new object which also has a propery (2.2 style),
whose value you can also specify, or the object will belong to
the default category with prop==None. The class keeps track of all
instances in categories [lists] of equal prop values. Actually
it's a dictionary with the properties for keys, and the corresponding
values are lists of weak references to wrapper objects with that key
as property value.

If you update the property of a wrapper object, it's prop value category
membership is automatically updated, and likewise if a wrapper object
is deleted (using weak references seems to work in allowing the ref
count to go to zero and the destructor gets called) ;-).

The access methods to get lists of objects etc are accessible as
methods through any wrapper object instance.

The getCategorizerClass function delivers a class with a separate
{prop_value:[obj_weak_refs]} dictionary, to that several distinct
categories can operate separately. I used a list below (ulist) of
instances to bind the wrapper objects, but they can be bound any
way that keeps them alive until you want to delete them.

I'm not sure this is a practical solution to your problem, but it
was an interesting exercise. I'd be interested in a clean and proper
meta-class solution to generating the Category classes that
categorizer.getCategorizerClass() returns.

Regards,
Bengt Richter

______________________________________________________________

 Python 2.2 (#28, Dec 21 2001, 12:21:22) [MSC 32 bit (Intel)] on win32
 Type "help", "copyright", "credits" or "license" for more information.
 >>> import categorizer
 >>> NamePriv = categorizer.getCategorizerClass()
 >>> ulist = [NamePriv('Bob',1), NamePriv('Jim',2), NamePriv('Pete',2)]
 >>> ulist[0].get_objs(1)
 ['Bob']
 >>> ulist[0].get_objs(2)
 ['Jim', 'Pete']
 >>> ulist[1].prop = 1
 >>> ulist[0].get_objs(1)
 ['Bob', 'Jim']
 >>> ulist[0].get_objs(2)
 ['Pete']
 >>> del ulist[0]
 >>> ulist[0].get_objs(1)
 ['Jim']
 >>> ulist[0].get_objs(2)
 ['Pete']
 >>> ulist[0].prop
 1
 >>> ulist[0].obj
 'Jim'
 >>> ulist[0].prop =2
 >>> ulist[0].get_objs(1)
 []
 >>> ulist[0].get_objs(2)
 ['Pete', 'Jim']
 >>> ulist[0].get_obj(2)
 'Pete'

(Note that get_obj gets only the first available, unlike get_objs (plural)).
______________________________________________________________

# categorizer.py
# (strawman discussion example, not production code)
"""Use getCategorizerClass([dict]) to get a Categorizer class"""

import weakref

def getCategorizerClass(d=None):
    """getCategorizerClass([dict]) => Categorizer class"""

    class Categorizer(object):
        """class to wrap object in another with categorizing property"""
        _pd = d or {}  #fresh d instance dict as class variable of form:
                 # { prop_value: [list of weak references to wrapper instances having a given prop value] }
        def __init__(self, v=None, p=None):
            """init Categorizer box instance with obj and property"""
            self.__doc__ = """instance of class Categorizer having property prop"""
            self.obj = v  # the obj in the box
            self.wsr = weakref.ref(self)  # weak self ref to use in dict
            self.prop = p   # triggers set_prop to add to list of objects with p as property

        def __del__(self):
            try:
               self._pd[self._prop].remove(self.wsr) #remove self from current prop's list
               del self.wsr
            except:
                pass

        def get_cat_boxes(self,v=None):
            """find Categorizer box instance(s) whose property is a given value"""
            return filter(None, [y() for y in (self._pd.get(v) or [])])

        def get_objs(self,v=None):
            """get objs from Categorizer box instance(s) whose property is a given value"""
            return [x.obj for x in filter(None, [y() for y in (self._pd.get(v) or [])])]

        def get_obj(self,v=None):
            """get first available obj from Categorizer box instance(s) whose property is a given value"""
            for y in (self._pd.get(v) or []):
                yo = y()                # get obj from weak ref
                if yo: return yo.obj    # return first found only
            return None                 # none found

        def get_prop(self):
            """triggered by box_instance.prop in expression"""
            return self._prop
        def set_prop(self, p):
            """triggered by box_instance.prop on left hand side of '='"""
            try:
               self._pd[self._prop].remove(self.wsr) #remove self from previous prop's list
            except:
                pass
            self._prop = p
            try:
                self._pd[p].append(self.wsr)      # put self on list for prop==p
            except:
                self._pd[p] = [self.wsr]          # ditto

        # tie in property methods
        prop = property(get_prop, set_prop, None, #no deleting the prop
                  "Property 'prop' of this instance")

    return Categorizer
______________________________________________________________




More information about the Python-list mailing list